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/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-admin/sop-admin-server/pom.xml b/sop-admin/sop-admin-server/pom.xml index e2bf8da2..5b5fb943 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-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/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 e5aa91ac..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 @@ -2,18 +2,28 @@ 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.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 lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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 javax.servlet.http.HttpServletRequest; +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; @@ -25,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 返回请求参数 */ @@ -38,6 +52,7 @@ public class ServerWebExchangeUtil { /** * 设置请求参数 + * * @param exchange ServerWebExchange * @param apiParam 请求参数 */ @@ -47,6 +62,7 @@ public class ServerWebExchangeUtil { /** * 获取Spring Cloud Gateway请求的原始参数。前提是要使用ReadBodyRoutePredicateFactory + * * @param exchange ServerWebExchange * @return 没有参数返回null * @see com.gitee.sop.gatewaycommon.gateway.route.ReadBodyRoutePredicateFactory @@ -69,7 +85,8 @@ public class ServerWebExchangeUtil { params = JSON.parseObject(cachedBody); } else if (StringUtils.containsIgnoreCase(contentTypeStr, "multipart")) { // 如果是文件上传请求 - HttpServletRequest fileUploadRequest = ServletFileUploadUtil.getFileUploadRequest(exchange, cachedBody); + HttpServletRequest fileUploadRequest = getFileUploadRequest(exchange, cachedBody); + setFileUploadRequest(exchange, fileUploadRequest); params = RequestUtil.convertMultipartRequestToMap(fileUploadRequest); } else { params = RequestUtil.parseQueryToMap(cachedBody); @@ -82,6 +99,7 @@ public class ServerWebExchangeUtil { return params; } + public static Map buildParams(MultiValueMap queryParams) { if (queryParams == null || queryParams.size() == 0) { return null; @@ -95,7 +113,8 @@ public class ServerWebExchangeUtil { /** * 添加header - * @param exchange 当前ServerWebExchange + * + * @param exchange 当前ServerWebExchange * @param headersConsumer headers * @return 返回一个新的ServerWebExchange */ @@ -105,12 +124,116 @@ public class ServerWebExchangeUtil { .mutate() .headers(headersConsumer) .build(); - // 将现在的request 变成 change对象 + // 创建一个新的exchange对象 return exchange .mutate() .request(serverHttpRequestNew) .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); + } + + 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 paramsConsumer 执行参数更改 + * @param headerConsumer header更改 + * @param 参数类型 + * @return 返回新的ServerWebExchange + */ + public static > ServerWebExchange format( + ServerWebExchange exchange + , T apiParam + , Consumer paramsConsumer + , 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) { + mediaType = MediaType.APPLICATION_FORM_URLENCODED; + } + paramsConsumer.accept(apiParam); + String contentType = mediaType.toString().toLowerCase(); + // 修改后的请求体 + // 处理json请求(application/json) + if (StringUtils.containsAny(contentType, "json", "text")) { + String bodyStr = JSON.toJSONString(apiParam); + 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); + } + } + 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/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 */ 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/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); - } - -} 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..479726be --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java @@ -0,0 +1,102 @@ +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.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 bodyDataBuffer; + private HttpHeaders httpHeaders; + private URI uri; + + /** + * ServerHttpRequest包装,作用类似于HttpServletRequestWrapper + * @param delegate 老的request + * @param queryString get请求后面的参数 + */ + public SopServerHttpRequestDecorator(ServerHttpRequest delegate, HttpHeaders newHeaders, String queryString) { + super(delegate); + 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.bodyDataBuffer = 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); + } + + @Override + public URI getURI() { + return uri == null ? super.getURI() : uri; + } + + @Override + public HttpHeaders getHeaders() { + return this.httpHeaders; + } + + @Override + 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/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..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 @@ -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; @@ -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 new file mode 100644 index 00000000..d015662b --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java @@ -0,0 +1,51 @@ +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 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; + +import static com.gitee.sop.gatewaycommon.gateway.filter.Orders.PARAMETER_FORMATTER_FILTER_ORDER; + +/** + * @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 = ServerWebExchangeUtil.getApiParam(exchange); + if (apiParam == null) { + return chain.filter(exchange); + } + // 校验成功后进行参数转换 + if (sopParameterFormatter != null) { + ServerWebExchange formatExchange = ServerWebExchangeUtil.format( + exchange + , apiParam + , sopParameterFormatter::format + , httpHeaders -> httpHeaders.set(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 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 66e3e928..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 @@ -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); @@ -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/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/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/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/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/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/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/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/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 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 { -} 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; 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 08b2e25f..e17aef98 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 c1b2f763..f800e269 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 b68791c7..4146a1c0 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