From b5008bad3201f6be3794338875af682b9cf561fb Mon Sep 17 00:00:00 2001 From: tanghc Date: Fri, 16 Aug 2019 14:48:48 +0800 Subject: [PATCH] =?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;