From 738572b21774c53bdef20fc5f5142ea6115ee999 Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 15 Aug 2019 18:04:30 +0800 Subject: [PATCH 1/6] =?UTF-8?q?gateway=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/common/ByteArrayStreamWrapper.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ByteArrayStreamWrapper.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ByteArrayStreamWrapper.java index 57ba85d6..93c592a3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ByteArrayStreamWrapper.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ByteArrayStreamWrapper.java @@ -4,13 +4,18 @@ import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import java.io.IOException; +/** + * byte数组流包装 + * + * @author tanghc + */ public class ByteArrayStreamWrapper extends ServletInputStream { private byte[] data; private int idx = 0; /** - * Creates a new ServletInputStreamWrapper instance. + * Creates a new ByteArrayStreamWrapper instance. * * @param data a byte[] value */ From 9d9c5ced4cbd1d791ef03ec346b309b8297f8cce Mon Sep 17 00:00:00 2001 From: tanghc Date: Thu, 15 Aug 2019 18:07:30 +0800 Subject: [PATCH 2/6] =?UTF-8?q?gateway=E6=94=AF=E6=8C=81=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/ServerWebExchangeUtil.java | 17 ++++++++++++++-- .../gateway/common/ServletFileUploadUtil.java | 20 ------------------- 2 files changed, 15 insertions(+), 22 deletions(-) delete mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ServletFileUploadUtil.java diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index e5aa91ac..09848028 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -2,7 +2,7 @@ package com.gitee.sop.gatewaycommon.gateway; import com.alibaba.fastjson.JSON; import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.gitee.sop.gatewaycommon.gateway.common.ServletFileUploadUtil; +import com.gitee.sop.gatewaycommon.gateway.common.FileUploadHttpServletRequest; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.util.RequestUtil; import org.apache.commons.lang3.StringUtils; @@ -14,6 +14,7 @@ import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; import javax.servlet.http.HttpServletRequest; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -69,7 +70,7 @@ public class ServerWebExchangeUtil { params = JSON.parseObject(cachedBody); } else if (StringUtils.containsIgnoreCase(contentTypeStr, "multipart")) { // 如果是文件上传请求 - HttpServletRequest fileUploadRequest = ServletFileUploadUtil.getFileUploadRequest(exchange, cachedBody); + HttpServletRequest fileUploadRequest = getFileUploadRequest(exchange, cachedBody); params = RequestUtil.convertMultipartRequestToMap(fileUploadRequest); } else { params = RequestUtil.parseQueryToMap(cachedBody); @@ -112,5 +113,17 @@ public class ServerWebExchangeUtil { .build(); } + /** + * 获取一个文件上传request + * + * @param exchange 当前ServerWebExchange + * @param requestBody 上传文件请求体内容 + * @return 返回文件上传request + */ + public static HttpServletRequest getFileUploadRequest(ServerWebExchange exchange, String requestBody) { + byte[] data = requestBody.getBytes(StandardCharsets.UTF_8); + return new FileUploadHttpServletRequest(exchange.getRequest(), data); + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ServletFileUploadUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ServletFileUploadUtil.java deleted file mode 100644 index 9cb299c6..00000000 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/ServletFileUploadUtil.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.gitee.sop.gatewaycommon.gateway.common; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.server.ServerWebExchange; - -import javax.servlet.http.HttpServletRequest; -import java.nio.charset.StandardCharsets; - -/** - * @author tanghc - */ -@Slf4j -public class ServletFileUploadUtil { - - public static HttpServletRequest getFileUploadRequest(ServerWebExchange exchange, String requestBody) { - byte[] data = requestBody.getBytes(StandardCharsets.UTF_8); - return new FileUploadHttpServletRequest(exchange.getRequest(), data); - } - -} From 5a56b5f98b6b99f3fba51de23e5eed918d87c188 Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 16 Aug 2019 09:02:40 +0800 Subject: [PATCH 3/6] =?UTF-8?q?gateway=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/docs/_sidebar.md | 64 +++++++++---------- doc/docs/files/10111_动态修改请求参数.md | 2 +- .../sop/gatewaycommon/bean/ApiConfig.java | 4 +- .../gateway/ServerWebExchangeUtil.java | 12 ++++ .../BaseGatewayConfiguration.java | 6 ++ .../gateway/filter/LimitFilter.java | 4 +- .../filter/ParameterFormatterFilter.java | 41 ++++++++++++ .../gateway/filter/ValidateFilter.java | 4 +- .../gateway/param/GatewayParamBuilder.java | 6 +- .../NameVersionRoutePredicateFactory.java | 14 ++-- .../manager/AbstractConfiguration.java | 8 +++ ...ParameterFormatter.java => Formatter.java} | 2 +- .../param/ParameterFormatter.java | 10 +++ .../configuration/BaseZuulConfiguration.java | 8 --- .../filter/PreParameterFormatterFilter.java | 8 +-- .../zuul/param/ZuulParameterFormatter.java | 10 --- 16 files changed, 132 insertions(+), 71 deletions(-) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java rename sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/{ParameterFormatter.java => Formatter.java} (82%) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParameterFormatter.java delete mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java diff --git a/doc/docs/_sidebar.md b/doc/docs/_sidebar.md index 767cf8cc..d201e865 100644 --- a/doc/docs/_sidebar.md +++ b/doc/docs/_sidebar.md @@ -1,34 +1,34 @@ -* [首页](/?t=1565767132305) +* [首页](/?t=1565916799573) * 开发文档 - * [快速体验](files/10010_快速体验.md?t=1565767132307) - * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1565767132325) - * [新增接口](files/10020_新增接口.md?t=1565767132325) - * [业务参数校验](files/10030_业务参数校验.md?t=1565767132325) - * [错误处理](files/10040_错误处理.md?t=1565767132325) - * [编写文档](files/10041_编写文档.md?t=1565767132326) - * [接口交互详解](files/10050_接口交互详解.md?t=1565767132326) - * [easyopen支持](files/10070_easyopen支持.md?t=1565767132326) - * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1565767132326) - * [ISV管理](files/10085_ISV管理.md?t=1565767132326) - * [自定义路由](files/10086_自定义路由.md?t=1565767132326) - * [自定义返回结果](files/10087_自定义返回结果.md?t=1565767132326) - * [自定义过滤器](files/10088_自定义过滤器.md?t=1565767132326) - * [路由授权](files/10090_路由授权.md?t=1565767132326) - * [接口限流](files/10092_接口限流.md?t=1565767132326) - * [监控日志](files/10093_监控日志.md?t=1565767132327) - * [SDK开发](files/10095_SDK开发.md?t=1565767132327) - * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1565767132327) - * [应用授权](files/10097_应用授权.md?t=1565767132327) - * [传统web开发](files/10100_传统web开发.md?t=1565767132327) - * [文件上传](files/10104_文件上传.md?t=1565767132327) - * [nacos注册中心](files/10106_nacos注册中心.md?t=1565767132327) - * [扩展其它注册中心](files/10107_扩展其它注册中心.md?t=1565767132327) - * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1565767132327) - * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1565767132327) - * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1565767132327) + * [快速体验](files/10010_快速体验.md?t=1565916799577) + * [项目接入到SOP](files/10011_项目接入到SOP.md?t=1565916799596) + * [新增接口](files/10020_新增接口.md?t=1565916799596) + * [业务参数校验](files/10030_业务参数校验.md?t=1565916799596) + * [错误处理](files/10040_错误处理.md?t=1565916799596) + * [编写文档](files/10041_编写文档.md?t=1565916799596) + * [接口交互详解](files/10050_接口交互详解.md?t=1565916799597) + * [easyopen支持](files/10070_easyopen支持.md?t=1565916799597) + * [使用签名校验工具](files/10080_使用签名校验工具.md?t=1565916799597) + * [ISV管理](files/10085_ISV管理.md?t=1565916799597) + * [自定义路由](files/10086_自定义路由.md?t=1565916799597) + * [自定义返回结果](files/10087_自定义返回结果.md?t=1565916799597) + * [自定义过滤器](files/10088_自定义过滤器.md?t=1565916799597) + * [路由授权](files/10090_路由授权.md?t=1565916799598) + * [接口限流](files/10092_接口限流.md?t=1565916799598) + * [监控日志](files/10093_监控日志.md?t=1565916799598) + * [SDK开发](files/10095_SDK开发.md?t=1565916799598) + * [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1565916799598) + * [应用授权](files/10097_应用授权.md?t=1565916799598) + * [传统web开发](files/10100_传统web开发.md?t=1565916799598) + * [文件上传](files/10104_文件上传.md?t=1565916799598) + * [nacos注册中心](files/10106_nacos注册中心.md?t=1565916799599) + * [扩展其它注册中心](files/10107_扩展其它注册中心.md?t=1565916799599) + * [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1565916799599) + * [预发布灰度发布](files/10110_预发布灰度发布.md?t=1565916799599) + * [动态修改请求参数](files/10111_动态修改请求参数.md?t=1565916799599) * 原理分析 - * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1565767132328) - * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1565767132328) - * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1565767132328) - * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1565767132328) - * [常见问题](files/90100_常见问题.md?t=1565767132328) + * [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1565916799599) + * [原理分析之路由存储](files/90011_原理分析之路由存储.md?t=1565916799599) + * [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1565916799599) + * [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1565916799600) + * [常见问题](files/90100_常见问题.md?t=1565916799600) diff --git a/doc/docs/files/10111_动态修改请求参数.md b/doc/docs/files/10111_动态修改请求参数.md index 90f2f7f4..b8d1d89f 100644 --- a/doc/docs/files/10111_动态修改请求参数.md +++ b/doc/docs/files/10111_动态修改请求参数.md @@ -14,7 +14,7 @@ ```java public static void main(String[] args) { - ApiConfig.getInstance().setZuulParameterFormatter(requestParams -> { + ApiConfig.getInstance().setParameterFormatter(requestParams -> { // 获取biz_content JSONObject jsonObject = requestParams.getJSONObject(ParamNames.BIZ_CONTENT_NAME); // 修改biz_content中的值 diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java index ab6fb813..a61e9f6a 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java @@ -18,6 +18,7 @@ import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; import com.gitee.sop.gatewaycommon.param.ParamBuilder; +import com.gitee.sop.gatewaycommon.param.ParameterFormatter; import com.gitee.sop.gatewaycommon.result.DataNameBuilder; import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder; import com.gitee.sop.gatewaycommon.result.ResultAppender; @@ -34,7 +35,6 @@ import com.gitee.sop.gatewaycommon.validate.Signer; import com.gitee.sop.gatewaycommon.validate.Validator; import com.gitee.sop.gatewaycommon.zuul.configuration.ZuulErrorController; import com.gitee.sop.gatewaycommon.zuul.param.ZuulParamBuilder; -import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; import com.gitee.sop.gatewaycommon.zuul.result.ZuulResultExecutor; import com.netflix.zuul.context.RequestContext; import lombok.Data; @@ -150,7 +150,7 @@ public class ApiConfig { */ private ZuulErrorController zuulErrorController = new ZuulErrorController(); - private ZuulParameterFormatter zuulParameterFormatter; + private ParameterFormatter parameterFormatter; // -------- fields --------- diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index 09848028..d1e7a84f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -125,5 +125,17 @@ public class ServerWebExchangeUtil { return new FileUploadHttpServletRequest(exchange.getRequest(), data); } + /** + * 修改请求参数 + * @param exchange ServerWebExchange + * @param apiParam 请求参数 + * @param consumer 执行参数更改 + * @param 参数类型 + * @return 返回新的ServerWebExchange + */ + public static > ServerWebExchange format(ServerWebExchange exchange, T apiParam, Consumer consumer) { + + return null; + } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java index 5a3c2b6e..badbd26f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/configuration/BaseGatewayConfiguration.java @@ -3,6 +3,7 @@ package com.gitee.sop.gatewaycommon.gateway.configuration; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.gateway.filter.GatewayModifyResponseGatewayFilter; import com.gitee.sop.gatewaycommon.gateway.filter.LoadBalancerClientExtFilter; +import com.gitee.sop.gatewaycommon.gateway.filter.ParameterFormatterFilter; import com.gitee.sop.gatewaycommon.gateway.filter.ValidateFilter; import com.gitee.sop.gatewaycommon.gateway.handler.GatewayExceptionHandler; import com.gitee.sop.gatewaycommon.gateway.route.GatewayRouteRepository; @@ -106,4 +107,9 @@ public class BaseGatewayConfiguration extends AbstractConfiguration { return gatewayRouteRepository; } + @Bean + ParameterFormatterFilter parameterFormatterFilter() { + return new ParameterFormatterFilter(); + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java index ae7573c4..872df6d1 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java @@ -3,7 +3,7 @@ package com.gitee.sop.gatewaycommon.gateway.filter; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ConfigLimitDto; import com.gitee.sop.gatewaycommon.exception.ApiException; -import com.gitee.sop.gatewaycommon.gateway.GatewayContext; +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.limit.LimitManager; import com.gitee.sop.gatewaycommon.limit.LimitType; import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; @@ -34,7 +34,7 @@ public class LimitFilter implements GlobalFilter, Ordered { if (!apiConfig.isOpenLimit()) { return chain.filter(exchange); } - ApiParam apiParam = GatewayContext.getApiParam(exchange); + ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange); ConfigLimitDto configLimitDto = this.findConfigLimitDto(apiConfig, apiParam, exchange); if (configLimitDto == null) { return null; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java new file mode 100644 index 00000000..5a15a658 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java @@ -0,0 +1,41 @@ +package com.gitee.sop.gatewaycommon.gateway.filter; + +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.param.ParameterFormatter; +import com.gitee.sop.gatewaycommon.zuul.ZuulContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * @author tanghc + */ +@Slf4j +public class ParameterFormatterFilter implements GlobalFilter, Ordered { + + @Autowired(required = false) + private ParameterFormatter sopParameterFormatter; + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ApiParam apiParam = ZuulContext.getApiParam(); + // 校验成功后进行参数转换 + if (sopParameterFormatter != null) { + ServerWebExchange formatExchange = ServerWebExchangeUtil.format(exchange, apiParam, sopParameterFormatter::format); + ServerWebExchange serverWebExchange = ServerWebExchangeUtil.addHeaders(formatExchange, httpHeaders -> httpHeaders.add(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion())); + return chain.filter(serverWebExchange); + } + return chain.filter(exchange); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java index 66e3e928..4a038386 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java @@ -1,7 +1,7 @@ package com.gitee.sop.gatewaycommon.gateway.filter; import com.gitee.sop.gatewaycommon.exception.ApiException; -import com.gitee.sop.gatewaycommon.gateway.GatewayContext; +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.validate.Validator; @@ -29,7 +29,7 @@ public class ValidateFilter implements GlobalFilter, Ordered { public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 解析参数 ApiParam param = paramBuilder.build(exchange); - GatewayContext.setApiParam(exchange, param); + ServerWebExchangeUtil.setApiParam(exchange, param); // 验证操作,这里有负责验证签名参数 try { validator.validate(param); diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java index dcdbe855..2867b184 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/param/GatewayParamBuilder.java @@ -1,6 +1,6 @@ package com.gitee.sop.gatewaycommon.gateway.param; -import com.gitee.sop.gatewaycommon.gateway.GatewayContext; +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.param.BaseParamBuilder; import org.springframework.web.server.ServerWebExchange; @@ -13,8 +13,8 @@ import java.util.Map; public class GatewayParamBuilder extends BaseParamBuilder { @Override - public Map buildRequestParams(ServerWebExchange exchange) { - Map params = GatewayContext.getRequestParams(exchange); + public Map buildRequestParams(ServerWebExchange exchange) { + Map params = ServerWebExchangeUtil.getRequestParams(exchange); return params == null ? Collections.emptyMap() : params; } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java index 10ffb40e..cb8a0a86 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/route/NameVersionRoutePredicateFactory.java @@ -1,7 +1,6 @@ package com.gitee.sop.gatewaycommon.gateway.route; -import com.gitee.sop.gatewaycommon.bean.SopConstants; -import com.gitee.sop.gatewaycommon.gateway.GatewayContext; +import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.param.ParamNames; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory; @@ -45,14 +44,17 @@ public class NameVersionRoutePredicateFactory extends AbstractRoutePredicateFact public Predicate apply(Config config) { return exchange -> { - Map params = GatewayContext.getRequestParams(exchange); + Map params = ServerWebExchangeUtil.getRequestParams(exchange); if (CollectionUtils.isEmpty(params)) { return false; } String nameVersion = config.param; - String name = params.getOrDefault(ParamNames.API_NAME, SopConstants.UNKNOWN_METHOD); - String version = params.getOrDefault(ParamNames.VERSION_NAME, ""); - return (name + version).equals(nameVersion); + Object name = params.get(ParamNames.API_NAME); + Object version = params.get(ParamNames.VERSION_NAME); + if (name == null || version == null) { + return false; + } + return (name.toString() + version).equals(nameVersion); }; } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java index 9b01bd32..af742251 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/AbstractConfiguration.java @@ -6,6 +6,7 @@ import com.gitee.sop.gatewaycommon.bean.BeanInitializer; import com.gitee.sop.gatewaycommon.bean.SpringContext; import com.gitee.sop.gatewaycommon.limit.LimitManager; import com.gitee.sop.gatewaycommon.message.ErrorFactory; +import com.gitee.sop.gatewaycommon.param.ParameterFormatter; import com.gitee.sop.gatewaycommon.secret.IsvManager; import com.gitee.sop.gatewaycommon.session.SessionManager; import com.gitee.sop.gatewaycommon.validate.Validator; @@ -93,6 +94,13 @@ public class AbstractConfiguration implements ApplicationContextAware { return ApiConfig.getInstance().getSessionManager(); } + @Bean + @ConditionalOnMissingBean + ParameterFormatter sopParameterFormatter(){ + return ApiConfig.getInstance().getParameterFormatter(); + } + + /** * 跨域过滤器 * diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/Formatter.java similarity index 82% rename from sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java rename to sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/Formatter.java index 8fd2caf7..697f2ec8 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/Formatter.java @@ -7,7 +7,7 @@ import java.util.Map; * * @author tanghc */ -public interface ParameterFormatter> { +public interface Formatter> { /** * 参数格式化,即动态修改请求参数 diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParameterFormatter.java new file mode 100644 index 00000000..92a7f7f6 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/ParameterFormatter.java @@ -0,0 +1,10 @@ +package com.gitee.sop.gatewaycommon.param; + +import com.alibaba.fastjson.JSONObject; +import com.gitee.sop.gatewaycommon.manager.Formatter; + +/** + * @author tanghc + */ +public interface ParameterFormatter extends Formatter { +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java index e93c5a33..f0470ec0 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java @@ -1,10 +1,8 @@ package com.gitee.sop.gatewaycommon.zuul.configuration; -import com.alibaba.fastjson.JSONObject; import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; -import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteRepositoryContext; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter; @@ -47,12 +45,6 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return ApiConfig.getInstance().getZuulParamBuilder(); } - @Bean - @ConditionalOnMissingBean - ParameterFormatter preParamFilter(){ - return ApiConfig.getInstance().getZuulParameterFormatter(); - } - /** * 路由存储 * @return diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java index 9f88470c..e7f725b4 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreParameterFormatterFilter.java @@ -2,8 +2,8 @@ package com.gitee.sop.gatewaycommon.zuul.filter; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamNames; +import com.gitee.sop.gatewaycommon.param.ParameterFormatter; import com.gitee.sop.gatewaycommon.zuul.ZuulContext; -import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterFormatter; import com.gitee.sop.gatewaycommon.zuul.param.ZuulParameterUtil; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; @@ -17,7 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; public class PreParameterFormatterFilter extends BaseZuulFilter { @Autowired(required = false) - private ZuulParameterFormatter zuulParameterFormatter; + private ParameterFormatter sopParameterFormatter; @Override protected FilterType getFilterType() { @@ -33,8 +33,8 @@ public class PreParameterFormatterFilter extends BaseZuulFilter { protected Object doRun(RequestContext requestContext) throws ZuulException { ApiParam apiParam = ZuulContext.getApiParam(); // 校验成功后进行参数转换 - if (zuulParameterFormatter != null) { - ZuulParameterUtil.format(apiParam, zuulParameterFormatter::format); + if (sopParameterFormatter != null) { + ZuulParameterUtil.format(apiParam, sopParameterFormatter::format); requestContext.addZuulRequestHeader(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()); } return null; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java deleted file mode 100644 index 23885acd..00000000 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterFormatter.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.gitee.sop.gatewaycommon.zuul.param; - -import com.alibaba.fastjson.JSONObject; -import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; - -/** - * @author tanghc - */ -public interface ZuulParameterFormatter extends ParameterFormatter { -} From de8ad5ffaa6fb76cd88b7091c6307fce4f18066a Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 16 Aug 2019 11:13:01 +0800 Subject: [PATCH 4/6] =?UTF-8?q?gateway=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gateway/ServerWebExchangeUtil.java | 68 +++++++++++++++++-- .../common/SopServerHttpRequestDecorator.java | 65 ++++++++++++++++++ .../gateway/filter/LimitFilter.java | 2 +- .../gatewaycommon/gateway/filter/Orders.java | 14 +++- .../filter/ParameterFormatterFilter.java | 25 +++++-- .../gateway/filter/ValidateFilter.java | 2 +- .../zuul/filter/BaseZuulFilter.java | 3 + .../zuul/filter/PreVersionDecisionFilter.java | 2 +- 8 files changed, 166 insertions(+), 15 deletions(-) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index d1e7a84f..76129ba7 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -3,17 +3,23 @@ package com.gitee.sop.gatewaycommon.gateway; import com.alibaba.fastjson.JSON; import com.gitee.sop.gatewaycommon.bean.SopConstants; import com.gitee.sop.gatewaycommon.gateway.common.FileUploadHttpServletRequest; +import com.gitee.sop.gatewaycommon.gateway.common.SopServerHttpRequestDecorator; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.util.RequestUtil; +import io.netty.buffer.ByteBufAllocator; import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.MultiValueMap; import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; @@ -126,16 +132,70 @@ public class ServerWebExchangeUtil { } /** - * 修改请求参数 + * 修改请求参数。参考自:https://blog.csdn.net/fuck487/article/details/85166162 * @param exchange ServerWebExchange * @param apiParam 请求参数 - * @param consumer 执行参数更改 + * @param paramsConsumer 执行参数更改 + * @param headerConsumer header更改 * @param 参数类型 - * @return 返回新的ServerWebExchange + * @return 返回新的ServerWebExchange,参数没有被修改则返回null */ - public static > ServerWebExchange format(ServerWebExchange exchange, T apiParam, Consumer consumer) { + public static > ServerWebExchange format( + ServerWebExchange exchange + , T apiParam + , Consumer paramsConsumer + , Consumer headerConsumer + ) { + ServerHttpRequest serverHttpRequest = exchange.getRequest(); + if (serverHttpRequest.getMethod() == HttpMethod.GET) { + paramsConsumer.accept(apiParam); + } else { + MediaType mediaType = serverHttpRequest.getHeaders().getContentType(); + if (mediaType == null) { + return null; + } + paramsConsumer.accept(apiParam); + String contentType = mediaType.toString().toLowerCase(); + if (StringUtils.containsAny(contentType, "json", "text")) { + //下面的将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值 + URI uri = serverHttpRequest.getURI(); + URI newUri = UriComponentsBuilder.fromUri(uri).build(true).toUri(); + ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build(); + + // 定义新的消息头 + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + + // 自定义header + headerConsumer.accept(headers); + // 修改后的请求体 + String bodyStr = JSON.toJSONString(apiParam); + byte[] bodyStrBytes = bodyStr.getBytes(StandardCharsets.UTF_8); + + // 由于post的body只能订阅一次,由于上面代码中已经订阅过一次body。 + // 所以要再次封装请求到request才行,不然会报错请求已经订阅过 + request = new SopServerHttpRequestDecorator(request, bodyStrBytes, headers); + + return exchange.mutate().request(request).build(); + } else { + + } + } return null; } + /** + * 字符串转DataBuffer + * @param value 值 + * @return 返回buffer + */ + private static DataBuffer stringBuffer(String value) { + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); + DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + return buffer; + } + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java new file mode 100644 index 00000000..cb4e0da8 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java @@ -0,0 +1,65 @@ +package com.gitee.sop.gatewaycommon.gateway.common; + +import io.netty.buffer.ByteBufAllocator; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.NettyDataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import reactor.core.publisher.Flux; + +/** + * @author tanghc + */ +public class SopServerHttpRequestDecorator extends ServerHttpRequestDecorator { + + private Flux bodyData; + private HttpHeaders httpHeaders; + + public SopServerHttpRequestDecorator(ServerHttpRequest delegate, byte[] bodyData, HttpHeaders httpHeaders) { + super(delegate); + if (httpHeaders == null) { + throw new IllegalArgumentException("httpHeaders can not be null."); + } + if (bodyData == null) { + throw new IllegalArgumentException("bodyData can not be null."); + } + // 由于请求体已改变,这里要重新设置contentLength + int contentLength = bodyData.length; + httpHeaders.setContentLength(contentLength); + + if (contentLength <= 0) { + // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + } + + this.httpHeaders = httpHeaders; + this.bodyData = stringBuffer(bodyData); + } + + /** + * 字符串转DataBuffer + * @param bytes 请求体 + * @return 返回buffer + */ + private static Flux stringBuffer(byte[] bytes) { + NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); + DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + return Flux.just(buffer); + } + + private SopServerHttpRequestDecorator(ServerHttpRequest delegate) { + super(delegate); + } + + @Override + public Flux getBody() { + return bodyData == null ? super.getBody() : bodyData; + } + + @Override + public HttpHeaders getHeaders() { + return httpHeaders == null ? super.getHeaders() : httpHeaders; + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java index 872df6d1..c24ef5d3 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java @@ -59,7 +59,7 @@ public class LimitFilter implements GlobalFilter, Ordered { @Override public int getOrder() { - return Orders.LIMIT_ORDER; + return Orders.LIMIT_FILTER_ORDER; } protected ConfigLimitDto findConfigLimitDto(ApiConfig apiConfig, ApiParam apiParam, ServerWebExchange exchange) { diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/Orders.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/Orders.java index 1485d969..cd3db928 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/Orders.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/Orders.java @@ -7,8 +7,18 @@ import org.springframework.core.Ordered; */ public class Orders { /** 验证拦截器order */ - public static final int VALIDATE_ORDER = Ordered.HIGHEST_PRECEDENCE + 1000; + public static final int VALIDATE_FILTER_ORDER = Ordered.HIGHEST_PRECEDENCE + 1000; + + /** 参数格式化过滤器 */ + public static final int PARAMETER_FORMATTER_FILTER_ORDER = VALIDATE_FILTER_ORDER + 1; + + /** 权限验证过滤 */ + public static final int PRE_ROUTE_PERMISSION_FILTER_ORDER = PARAMETER_FORMATTER_FILTER_ORDER + 100; /** 验证拦截器order */ - public static final int LIMIT_ORDER = VALIDATE_ORDER + 1; + public static final int LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 100; + + /** 决定版本号过滤器 */ + public static final int VERSION_DECISION_FILTER_ORDER = LIMIT_FILTER_ORDER + 100; + } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java index 5a15a658..1624a680 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java @@ -4,7 +4,6 @@ import com.gitee.sop.gatewaycommon.gateway.ServerWebExchangeUtil; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamNames; import com.gitee.sop.gatewaycommon.param.ParameterFormatter; -import com.gitee.sop.gatewaycommon.zuul.ZuulContext; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; @@ -13,6 +12,8 @@ import org.springframework.core.Ordered; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import static com.gitee.sop.gatewaycommon.gateway.filter.Orders.PARAMETER_FORMATTER_FILTER_ORDER; + /** * @author tanghc */ @@ -24,18 +25,30 @@ public class ParameterFormatterFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ApiParam apiParam = ZuulContext.getApiParam(); + ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange); + if (apiParam == null) { + return chain.filter(exchange); + } // 校验成功后进行参数转换 if (sopParameterFormatter != null) { - ServerWebExchange formatExchange = ServerWebExchangeUtil.format(exchange, apiParam, sopParameterFormatter::format); - ServerWebExchange serverWebExchange = ServerWebExchangeUtil.addHeaders(formatExchange, httpHeaders -> httpHeaders.add(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion())); - return chain.filter(serverWebExchange); + ServerWebExchange formatExchange = ServerWebExchangeUtil.format( + exchange + , apiParam + , sopParameterFormatter::format + , httpHeaders -> { + httpHeaders.remove(ParamNames.HEADER_VERSION_NAME); + httpHeaders.add(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()); + }); + if (formatExchange == null) { + return chain.filter(exchange); + } + return chain.filter(formatExchange); } return chain.filter(exchange); } @Override public int getOrder() { - return 0; + return PARAMETER_FORMATTER_FILTER_ORDER; } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java index 4a038386..72c6d582 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java @@ -43,6 +43,6 @@ public class ValidateFilter implements GlobalFilter, Ordered { @Override public int getOrder() { // 最优先执行 - return Orders.VALIDATE_ORDER; + return Orders.VALIDATE_FILTER_ORDER; } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java index 2147c1f3..77851c7b 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java @@ -32,6 +32,9 @@ public abstract class BaseZuulFilter extends ZuulFilter { /** 限流过滤 */ public static final int PRE_LIMIT_FILTER_ORDER = PRE_ROUTE_PERMISSION_FILTER_ORDER + 100; + /** 决定版本号过滤器 */ + public static final int PRE_VERSION_DECISION_FILTER_ORDER = PRE_LIMIT_FILTER_ORDER + 100; + private Integer filterOrder; /** diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java index d0198414..e8bcfef4 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java @@ -25,7 +25,7 @@ public class PreVersionDecisionFilter extends BaseZuulFilter { @Override protected int getFilterOrder() { - return PRE_LIMIT_FILTER_ORDER + 1; + return PRE_VERSION_DECISION_FILTER_ORDER; } @Override From b5008bad3201f6be3794338875af682b9cf561fb Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 16 Aug 2019 14:48:48 +0800 Subject: [PATCH 5/6] =?UTF-8?q?gateway=E5=8A=A8=E6=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sop/gatewaycommon/bean/SopConstants.java | 2 + .../gateway/ServerWebExchangeUtil.java | 136 ++++++++++------ .../common/FileUploadHttpServletRequest.java | 3 +- .../common/RequestContentDataExtractor.java | 154 ++++++++++++++++++ .../common/SopServerHttpRequestDecorator.java | 65 ++++++-- .../filter/ParameterFormatterFilter.java | 5 +- .../param/FormHttpOutputMessage.java | 33 ++++ .../sop/gatewaycommon/util/RequestUtil.java | 29 ++++ .../zuul/param/ZuulParameterUtil.java | 52 +----- 9 files changed, 361 insertions(+), 118 deletions(-) create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/RequestContentDataExtractor.java create mode 100644 sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/FormHttpOutputMessage.java diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java index 4a3f5c99..649f1a7f 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/SopConstants.java @@ -34,6 +34,8 @@ public class SopConstants { public static final String CACHE_API_PARAM = "cacheApiParam"; + public static final String CACHE_UPLOAD_REQUEST = "cacheUploadRequest"; + public static final String X_SERVICE_ERROR_CODE = "x-service-error-code"; public static final String X_SERVICE_ERROR_MESSAGE = "x-service-error-message"; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java index 76129ba7..884ed753 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java @@ -3,24 +3,27 @@ package com.gitee.sop.gatewaycommon.gateway; import com.alibaba.fastjson.JSON; import com.gitee.sop.gatewaycommon.bean.SopConstants; import com.gitee.sop.gatewaycommon.gateway.common.FileUploadHttpServletRequest; +import com.gitee.sop.gatewaycommon.gateway.common.RequestContentDataExtractor; import com.gitee.sop.gatewaycommon.gateway.common.SopServerHttpRequestDecorator; import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.param.FormHttpOutputMessage; import com.gitee.sop.gatewaycommon.util.RequestUtil; -import io.netty.buffer.ByteBufAllocator; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; -import java.net.URI; +import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,10 +35,14 @@ import static com.gitee.sop.gatewaycommon.bean.SopConstants.CACHE_REQUEST_BODY_O /** * @author tanghc */ +@Slf4j public class ServerWebExchangeUtil { + private static FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); + /** * 获取请求参数 + * * @param exchange ServerWebExchange * @return 返回请求参数 */ @@ -45,6 +52,7 @@ public class ServerWebExchangeUtil { /** * 设置请求参数 + * * @param exchange ServerWebExchange * @param apiParam 请求参数 */ @@ -54,6 +62,7 @@ public class ServerWebExchangeUtil { /** * 获取Spring Cloud Gateway请求的原始参数。前提是要使用ReadBodyRoutePredicateFactory + * * @param exchange ServerWebExchange * @return 没有参数返回null * @see com.gitee.sop.gatewaycommon.gateway.route.ReadBodyRoutePredicateFactory @@ -77,6 +86,7 @@ public class ServerWebExchangeUtil { } else if (StringUtils.containsIgnoreCase(contentTypeStr, "multipart")) { // 如果是文件上传请求 HttpServletRequest fileUploadRequest = getFileUploadRequest(exchange, cachedBody); + setFileUploadRequest(exchange, fileUploadRequest); params = RequestUtil.convertMultipartRequestToMap(fileUploadRequest); } else { params = RequestUtil.parseQueryToMap(cachedBody); @@ -89,6 +99,7 @@ public class ServerWebExchangeUtil { return params; } + public static Map buildParams(MultiValueMap queryParams) { if (queryParams == null || queryParams.size() == 0) { return null; @@ -102,7 +113,8 @@ public class ServerWebExchangeUtil { /** * 添加header - * @param exchange 当前ServerWebExchange + * + * @param exchange 当前ServerWebExchange * @param headersConsumer headers * @return 返回一个新的ServerWebExchange */ @@ -112,7 +124,7 @@ public class ServerWebExchangeUtil { .mutate() .headers(headersConsumer) .build(); - // 将现在的request 变成 change对象 + // 创建一个新的exchange对象 return exchange .mutate() .request(serverHttpRequestNew) @@ -122,23 +134,32 @@ public class ServerWebExchangeUtil { /** * 获取一个文件上传request * - * @param exchange 当前ServerWebExchange + * @param exchange 当前ServerWebExchange * @param requestBody 上传文件请求体内容 * @return 返回文件上传request */ public static HttpServletRequest getFileUploadRequest(ServerWebExchange exchange, String requestBody) { byte[] data = requestBody.getBytes(StandardCharsets.UTF_8); - return new FileUploadHttpServletRequest(exchange.getRequest(), data); + return new FileUploadHttpServletRequest(exchange.getRequest(), data); + } + + public static HttpServletRequest getFileUploadRequest(ServerWebExchange exchange) { + return exchange.getAttribute(SopConstants.CACHE_UPLOAD_REQUEST); + } + + public static void setFileUploadRequest(ServerWebExchange exchange, HttpServletRequest request) { + exchange.getAttributes().put(SopConstants.CACHE_UPLOAD_REQUEST, request); } /** * 修改请求参数。参考自:https://blog.csdn.net/fuck487/article/details/85166162 - * @param exchange ServerWebExchange - * @param apiParam 请求参数 + * + * @param exchange ServerWebExchange + * @param apiParam 原始请求参数 * @param paramsConsumer 执行参数更改 * @param headerConsumer header更改 - * @param 参数类型 - * @return 返回新的ServerWebExchange,参数没有被修改则返回null + * @param 参数类型 + * @return 返回新的ServerWebExchange */ public static > ServerWebExchange format( ServerWebExchange exchange @@ -147,55 +168,72 @@ public class ServerWebExchangeUtil { , Consumer headerConsumer ) { ServerHttpRequest serverHttpRequest = exchange.getRequest(); + HttpHeaders newHeaders = HttpHeaders.writableHttpHeaders(serverHttpRequest.getHeaders()); + // 新的request + ServerHttpRequest newRequest; if (serverHttpRequest.getMethod() == HttpMethod.GET) { paramsConsumer.accept(apiParam); - + // 新的查询参数 + String queryString = RequestUtil.convertMapToQueryString(apiParam); + // 创建一个新的request,并使用新的uri + newRequest = new SopServerHttpRequestDecorator(serverHttpRequest, newHeaders, queryString); } else { MediaType mediaType = serverHttpRequest.getHeaders().getContentType(); if (mediaType == null) { - return null; + mediaType = MediaType.APPLICATION_FORM_URLENCODED; } paramsConsumer.accept(apiParam); String contentType = mediaType.toString().toLowerCase(); + // 修改后的请求体 + // 处理json请求(application/json) if (StringUtils.containsAny(contentType, "json", "text")) { - //下面的将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值 - URI uri = serverHttpRequest.getURI(); - URI newUri = UriComponentsBuilder.fromUri(uri).build(true).toUri(); - ServerHttpRequest request = exchange.getRequest().mutate().uri(newUri).build(); - - // 定义新的消息头 - HttpHeaders headers = new HttpHeaders(); - headers.putAll(exchange.getRequest().getHeaders()); - - // 自定义header - headerConsumer.accept(headers); - // 修改后的请求体 String bodyStr = JSON.toJSONString(apiParam); - byte[] bodyStrBytes = bodyStr.getBytes(StandardCharsets.UTF_8); - - // 由于post的body只能订阅一次,由于上面代码中已经订阅过一次body。 - // 所以要再次封装请求到request才行,不然会报错请求已经订阅过 - request = new SopServerHttpRequestDecorator(request, bodyStrBytes, headers); - - return exchange.mutate().request(request).build(); + byte[] bodyBytes = bodyStr.getBytes(StandardCharsets.UTF_8); + newRequest = new SopServerHttpRequestDecorator(serverHttpRequest, newHeaders, bodyBytes); + } else if (StringUtils.contains(contentType, "multipart")) { + // 处理文件上传请求 + FormHttpOutputMessage outputMessage = new FormHttpOutputMessage(); + HttpServletRequest request = ServerWebExchangeUtil.getFileUploadRequest(exchange); + try { + // 转成MultipartRequest + if (!(request instanceof MultipartHttpServletRequest)) { + CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(); + request = commonsMultipartResolver.resolveMultipart(request); + } + // 重写新的值 + MultiValueMap builder = RequestContentDataExtractor.extract(request); + for (Map.Entry entry : apiParam.entrySet()) { + Object value = entry.getValue(); + if (value instanceof List) { + builder.put(entry.getKey(), (List) value); + } else { + builder.put(entry.getKey(), Collections.singletonList(String.valueOf(value))); + } + } + // 将字段以及上传文件重写写入到流中 + formHttpMessageConverter.write(builder, mediaType, outputMessage); + // 获取新的上传文件流 + byte[] bodyBytes = outputMessage.getInput(); + newRequest = new SopServerHttpRequestDecorator(serverHttpRequest, newHeaders, bodyBytes); + // 必须要重新指定content-type,因为此时的boundary已经发生改变 + MediaType contentTypeMultipart = outputMessage.getHeaders().getContentType(); + newRequest.getHeaders().setContentType(contentTypeMultipart); + } catch (IOException e) { + log.error("修改上传文件请求参数失败, apiParam:{}", apiParam, e); + throw new RuntimeException(e); + } } else { - + // 否则一律按表单请求处理 + String bodyStr = RequestUtil.convertMapToQueryString(apiParam); + byte[] bodyBytes = bodyStr.getBytes(StandardCharsets.UTF_8); + newRequest = new SopServerHttpRequestDecorator(serverHttpRequest, newHeaders, bodyBytes); } } - return null; - } - - /** - * 字符串转DataBuffer - * @param value 值 - * @return 返回buffer - */ - private static DataBuffer stringBuffer(String value) { - byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); - DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); - buffer.write(bytes); - return buffer; + HttpHeaders headers = newRequest.getHeaders(); + // 自定义header + headerConsumer.accept(headers); + // 创建一个新的exchange + return exchange.mutate().request(newRequest).build(); } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/FileUploadHttpServletRequest.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/FileUploadHttpServletRequest.java index 0a316372..1127c284 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/FileUploadHttpServletRequest.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/FileUploadHttpServletRequest.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.Principal; import java.util.Collection; +import java.util.Collections; import java.util.Enumeration; import java.util.Locale; import java.util.Map; @@ -250,7 +251,7 @@ public class FileUploadHttpServletRequest implements HttpServletRequest { @Override public Enumeration getParameterNames() { - return null; + return Collections.emptyEnumeration(); } @Override diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/RequestContentDataExtractor.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/RequestContentDataExtractor.java new file mode 100644 index 00000000..543f5e96 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/RequestContentDataExtractor.java @@ -0,0 +1,154 @@ +/* + * Copyright 2013-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.gitee.sop.gatewaycommon.gateway.common; + +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; + +import static java.util.Arrays.stream; +import static java.util.Collections.emptyMap; +import static org.springframework.util.StringUtils.isEmpty; +import static org.springframework.util.StringUtils.tokenizeToStringArray; +import static org.springframework.util.StringUtils.uriDecode; + +public class RequestContentDataExtractor { + public static MultiValueMap extract(HttpServletRequest request) throws IOException { + return (request instanceof MultipartHttpServletRequest) ? + extractFromMultipartRequest((MultipartHttpServletRequest) request) : + extractFromRequest(request); + } + + private static MultiValueMap extractFromRequest(HttpServletRequest request) throws IOException { + MultiValueMap builder = new LinkedMultiValueMap<>(); + Set queryParams = findQueryParams(request); + + for (Entry entry : request.getParameterMap().entrySet()) { + String key = entry.getKey(); + + if (!queryParams.contains(key) && entry.getValue() != null) { + for (String value : entry.getValue()) { + builder.add(key, value); + } + } + } + + return builder; + } + + private static MultiValueMap extractFromMultipartRequest(MultipartHttpServletRequest request) + throws IOException { + MultiValueMap builder = new LinkedMultiValueMap<>(); + Map> queryParamsGroupedByName = findQueryParamsGroupedByName( + request); + Set queryParams = findQueryParams(request); + + for (Entry entry : request.getParameterMap().entrySet()) { + String key = entry.getKey(); + List listOfAllParams = stream(request.getParameterMap().get(key)) + .collect(Collectors.toList()); + List listOfOnlyQueryParams = queryParamsGroupedByName.get(key); + + if(listOfOnlyQueryParams != null) { + listOfOnlyQueryParams = listOfOnlyQueryParams.stream() + .map(param -> uriDecode(param, Charset.defaultCharset())) + .collect(Collectors.toList()); + if (!listOfOnlyQueryParams.containsAll(listOfAllParams)) { + listOfAllParams.removeAll(listOfOnlyQueryParams); + for (String value : listOfAllParams) { + builder.add(key, + new HttpEntity<>(value, newHttpHeaders(request, key))); + } + } + } + + if (!queryParams.contains(key)) { + for (String value : entry.getValue()) { + builder.add(key, + new HttpEntity<>(value, newHttpHeaders(request, key))); + } + } + } + + for (Entry> parts : request.getMultiFileMap().entrySet()) { + for (MultipartFile file : parts.getValue()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentDispositionFormData(file.getName(), file.getOriginalFilename()); + if (file.getContentType() != null) { + headers.setContentType(MediaType.valueOf(file.getContentType())); + } + + HttpEntity entity = new HttpEntity<>(new InputStreamResource(file.getInputStream()), headers); + builder.add(parts.getKey(), entity); + } + } + + return builder; + } + + private static HttpHeaders newHttpHeaders(MultipartHttpServletRequest request, + String key) { + HttpHeaders headers = new HttpHeaders(); + String type = request.getMultipartContentType(key); + + if (type != null) { + headers.setContentType(MediaType.valueOf(type)); + } + return headers; + } + + private static Set findQueryParams(HttpServletRequest request) { + Set result = new HashSet<>(); + String query = request.getQueryString(); + + if (query != null) { + for (String value : tokenizeToStringArray(query, "&")) { + if (value.contains("=")) { + value = value.substring(0, value.indexOf("=")); + } + result.add(value); + } + } + + return result; + } + + static Map> findQueryParamsGroupedByName( + HttpServletRequest request) { + String query = request.getQueryString(); + if (isEmpty(query)) { + return emptyMap(); + } + return UriComponentsBuilder.fromUriString("?" + query).build().getQueryParams(); + } +} diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java index cb4e0da8..479726be 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java @@ -4,37 +4,73 @@ import io.netty.buffer.ByteBufAllocator; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.NettyDataBufferFactory; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.web.util.UriComponentsBuilder; import reactor.core.publisher.Flux; +import java.net.URI; + /** * @author tanghc */ public class SopServerHttpRequestDecorator extends ServerHttpRequestDecorator { - private Flux bodyData; + private Flux bodyDataBuffer; private HttpHeaders httpHeaders; + private URI uri; - public SopServerHttpRequestDecorator(ServerHttpRequest delegate, byte[] bodyData, HttpHeaders httpHeaders) { + /** + * ServerHttpRequest包装,作用类似于HttpServletRequestWrapper + * @param delegate 老的request + * @param queryString get请求后面的参数 + */ + public SopServerHttpRequestDecorator(ServerHttpRequest delegate, HttpHeaders newHeaders, String queryString) { super(delegate); - if (httpHeaders == null) { - throw new IllegalArgumentException("httpHeaders can not be null."); + if (delegate.getMethod() != HttpMethod.GET) { + throw new IllegalArgumentException("this constructor must be used by GET request."); } + if (queryString == null) { + throw new IllegalArgumentException("queryString can not be null."); + } + if (newHeaders == null) { + throw new IllegalArgumentException("newHeaders can not be null."); + } + + this.httpHeaders = newHeaders; + this.uri = UriComponentsBuilder.fromUri(delegate.getURI()) + .replaceQuery(queryString) + .build(true) + .toUri(); + } + + + + /** + * ServerHttpRequest包装,作用类似于HttpServletRequestWrapper + * @param delegate 老的request + * @param newHeaders 新的headers + * @param bodyData 请求体内容 + */ + public SopServerHttpRequestDecorator(ServerHttpRequest delegate, HttpHeaders newHeaders, byte[] bodyData) { + // 将请求体再次封装写回到request里,传到下一级,否则,由于请求体已被消费,后续的服务将取不到值 + super(delegate); if (bodyData == null) { throw new IllegalArgumentException("bodyData can not be null."); } + if (newHeaders == null) { + throw new IllegalArgumentException("newHeaders can not be null."); + } + this.httpHeaders = newHeaders; // 由于请求体已改变,这里要重新设置contentLength int contentLength = bodyData.length; httpHeaders.setContentLength(contentLength); - if (contentLength <= 0) { // TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); } - - this.httpHeaders = httpHeaders; - this.bodyData = stringBuffer(bodyData); + this.bodyDataBuffer = stringBuffer(bodyData); } /** @@ -49,17 +85,18 @@ public class SopServerHttpRequestDecorator extends ServerHttpRequestDecorator { return Flux.just(buffer); } - private SopServerHttpRequestDecorator(ServerHttpRequest delegate) { - super(delegate); + @Override + public URI getURI() { + return uri == null ? super.getURI() : uri; } @Override - public Flux getBody() { - return bodyData == null ? super.getBody() : bodyData; + public HttpHeaders getHeaders() { + return this.httpHeaders; } @Override - public HttpHeaders getHeaders() { - return httpHeaders == null ? super.getHeaders() : httpHeaders; + public Flux getBody() { + return bodyDataBuffer == null ? super.getBody() : bodyDataBuffer; } } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java index 1624a680..d015662b 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java @@ -35,10 +35,7 @@ public class ParameterFormatterFilter implements GlobalFilter, Ordered { exchange , apiParam , sopParameterFormatter::format - , httpHeaders -> { - httpHeaders.remove(ParamNames.HEADER_VERSION_NAME); - httpHeaders.add(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()); - }); + , httpHeaders -> httpHeaders.set(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion())); if (formatExchange == null) { return chain.filter(exchange); } diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/FormHttpOutputMessage.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/FormHttpOutputMessage.java new file mode 100644 index 00000000..b32123fa --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/param/FormHttpOutputMessage.java @@ -0,0 +1,33 @@ +package com.gitee.sop.gatewaycommon.param; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpOutputMessage; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author tanghc + */ +public class FormHttpOutputMessage implements HttpOutputMessage { + + private HttpHeaders headers = new HttpHeaders(); + private ByteArrayOutputStream output = new ByteArrayOutputStream(); + + @Override + public HttpHeaders getHeaders() { + return this.headers; + } + + @Override + public OutputStream getBody() throws IOException { + return this.output; + } + + public byte[] getInput() throws IOException { + this.output.flush(); + return this.output.toByteArray(); + } + +} \ No newline at end of file diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java index ed1a51ce..04315a71 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/util/RequestUtil.java @@ -1,6 +1,7 @@ package com.gitee.sop.gatewaycommon.util; import com.alibaba.fastjson.JSON; +import com.gitee.sop.gatewaycommon.bean.SopConstants; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; @@ -14,7 +15,10 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.URLDecoder; +import java.net.URLEncoder; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -67,6 +71,31 @@ public class RequestUtil { return params; } + /** + * 将map参数转换成查询参数 + * @return 返回aa=1&b=c... + */ + public static String convertMapToQueryString(Map apiParam) { + List list = new ArrayList<>(apiParam.size()); + try { + for (Map.Entry entry : apiParam.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Collection) { + Collection collection = (Collection) value; + for (Object el : collection) { + list.add(key + "=" + URLEncoder.encode(String.valueOf(el), SopConstants.UTF8)); + } + } else { + list.add(key + "=" + URLEncoder.encode(String.valueOf(value), SopConstants.UTF8)); + } + } + } catch (UnsupportedEncodingException e) { + log.error("字符集不支持", e); + } + return org.apache.commons.lang.StringUtils.join(list, "&"); + } + /** * request中的参数转换成map * diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java index d8e29c8d..ed8158ad 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/ZuulParameterUtil.java @@ -2,7 +2,7 @@ package com.gitee.sop.gatewaycommon.zuul.param; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.param.FormHttpOutputMessage; import com.gitee.sop.gatewaycommon.util.RequestUtil; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.http.HttpServletRequestWrapper; @@ -10,9 +10,7 @@ import com.netflix.zuul.http.ServletInputStreamWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.netflix.zuul.util.RequestContentDataExtractor; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.util.MultiValueMap; @@ -21,14 +19,8 @@ import org.springframework.web.multipart.commons.CommonsMultipartResolver; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -63,24 +55,7 @@ public class ZuulParameterUtil { byte[] bytes = json.getBytes(StandardCharsets.UTF_8); requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, bytes)); } else if(StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { - List list = new ArrayList<>(apiParam.size()); - try { - for (Map.Entry entry : apiParam.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (value instanceof Collection) { - Collection collection = (Collection) value; - for (Object el : collection) { - list.add(key + "=" + URLEncoder.encode(String.valueOf(el), SopConstants.UTF8)); - } - } else { - list.add(key + "=" + URLEncoder.encode(String.valueOf(value), SopConstants.UTF8)); - } - } - } catch (UnsupportedEncodingException e) { - log.error("字符集不支持", e); - } - String paramsStr = StringUtils.join(list, "&"); + String paramsStr = RequestUtil.convertMapToQueryString(apiParam); byte[] data = paramsStr.getBytes(StandardCharsets.UTF_8); requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); } else if(RequestUtil.isMultipart(request)) { @@ -128,29 +103,6 @@ public class ZuulParameterUtil { } } - - private static class FormHttpOutputMessage implements HttpOutputMessage { - - private HttpHeaders headers = new HttpHeaders(); - private ByteArrayOutputStream output = new ByteArrayOutputStream(); - - @Override - public HttpHeaders getHeaders() { - return this.headers; - } - - @Override - public OutputStream getBody() throws IOException { - return this.output; - } - - public byte[] getInput() throws IOException { - this.output.flush(); - return this.output.toByteArray(); - } - - } - private static class ChangeParamsHttpServletRequestWrapper extends HttpServletRequestWrapper { private byte[] data; From cbe0250f75d0a277d8fb4d3b58e17f26820eeaef Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 16 Aug 2019 14:50:07 +0800 Subject: [PATCH 6/6] 1.15.2 --- changelog.md | 5 +++++ sop-admin/sop-admin-server/pom.xml | 2 +- sop-common/pom.xml | 2 +- sop-common/sop-gateway-common/pom.xml | 4 ++-- sop-common/sop-registry-api/pom.xml | 2 +- sop-common/sop-service-common/pom.xml | 4 ++-- sop-example/sop-auth/pom.xml | 2 +- sop-example/sop-book/sop-book-web/pom.xml | 2 +- sop-example/sop-easyopen/pom.xml | 2 +- sop-example/sop-springmvc/pom.xml | 2 +- sop-example/sop-story/sop-story-web/pom.xml | 2 +- sop-gateway/pom.xml | 2 +- sop-website/website-server/pom.xml | 2 +- 13 files changed, 19 insertions(+), 14 deletions(-) diff --git a/changelog.md b/changelog.md index 3a943235..8059c5d1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # changelog +## 1.15.2 + +- 优化SpringCloudGateway上传文件功能 +- 优化SpringCloudGateway动态修改参数功能 + ## 1.15.1 - 修复未配置正确MessageConverter导致的异常 diff --git a/sop-admin/sop-admin-server/pom.xml b/sop-admin/sop-admin-server/pom.xml index fe60eb5d..6021c5b7 100644 --- a/sop-admin/sop-admin-server/pom.xml +++ b/sop-admin/sop-admin-server/pom.xml @@ -30,7 +30,7 @@ com.gitee.sop sop-registry-api - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT diff --git a/sop-common/pom.xml b/sop-common/pom.xml index 3812e07f..a040c4dc 100644 --- a/sop-common/pom.xml +++ b/sop-common/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.gitee.sop sop-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT pom diff --git a/sop-common/sop-gateway-common/pom.xml b/sop-common/sop-gateway-common/pom.xml index 01eb5160..7632cd29 100644 --- a/sop-common/sop-gateway-common/pom.xml +++ b/sop-common/sop-gateway-common/pom.xml @@ -5,11 +5,11 @@ com.gitee.sop sop-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT ../pom.xml sop-gateway-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT jar sop-gateway-common diff --git a/sop-common/sop-registry-api/pom.xml b/sop-common/sop-registry-api/pom.xml index 167b691d..a7a89cde 100644 --- a/sop-common/sop-registry-api/pom.xml +++ b/sop-common/sop-registry-api/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.gitee.sop sop-registry-api - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT UTF-8 diff --git a/sop-common/sop-service-common/pom.xml b/sop-common/sop-service-common/pom.xml index 89b0d9eb..f22638cb 100644 --- a/sop-common/sop-service-common/pom.xml +++ b/sop-common/sop-service-common/pom.xml @@ -6,11 +6,11 @@ com.gitee.sop sop-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT ../pom.xml sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT jar sop-service-common diff --git a/sop-example/sop-auth/pom.xml b/sop-example/sop-auth/pom.xml index 1f268e44..50ccf8c2 100644 --- a/sop-example/sop-auth/pom.xml +++ b/sop-example/sop-auth/pom.xml @@ -26,7 +26,7 @@ com.gitee.sop sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT org.springframework.cloud diff --git a/sop-example/sop-book/sop-book-web/pom.xml b/sop-example/sop-book/sop-book-web/pom.xml index 85f6dba6..71007355 100644 --- a/sop-example/sop-book/sop-book-web/pom.xml +++ b/sop-example/sop-book/sop-book-web/pom.xml @@ -24,7 +24,7 @@ com.gitee.sop sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT com.gitee.sop diff --git a/sop-example/sop-easyopen/pom.xml b/sop-example/sop-easyopen/pom.xml index b6fd5e41..1e2d9bfc 100644 --- a/sop-example/sop-easyopen/pom.xml +++ b/sop-example/sop-easyopen/pom.xml @@ -29,7 +29,7 @@ com.gitee.sop sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT org.springframework.cloud diff --git a/sop-example/sop-springmvc/pom.xml b/sop-example/sop-springmvc/pom.xml index a318d6e0..8596a4d6 100644 --- a/sop-example/sop-springmvc/pom.xml +++ b/sop-example/sop-springmvc/pom.xml @@ -20,7 +20,7 @@ com.gitee.sop sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT diff --git a/sop-example/sop-story/sop-story-web/pom.xml b/sop-example/sop-story/sop-story-web/pom.xml index d5310183..e94d488e 100644 --- a/sop-example/sop-story/sop-story-web/pom.xml +++ b/sop-example/sop-story/sop-story-web/pom.xml @@ -24,7 +24,7 @@ com.gitee.sop sop-service-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT com.gitee.sop diff --git a/sop-gateway/pom.xml b/sop-gateway/pom.xml index 266f1753..0f0d2f8e 100644 --- a/sop-gateway/pom.xml +++ b/sop-gateway/pom.xml @@ -23,7 +23,7 @@ com.gitee.sop sop-gateway-common - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT diff --git a/sop-website/website-server/pom.xml b/sop-website/website-server/pom.xml index 45186dfc..015d1e65 100644 --- a/sop-website/website-server/pom.xml +++ b/sop-website/website-server/pom.xml @@ -25,7 +25,7 @@ com.gitee.sop sop-registry-api - 1.15.1-SNAPSHOT + 1.15.2-SNAPSHOT