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 f76cd5ea..e0bbabbd 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 @@ -5,18 +5,19 @@ import com.gitee.sop.gatewaycommon.gateway.result.GatewayResult; import com.gitee.sop.gatewaycommon.gateway.result.GatewayResultExecutor; import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager; import com.gitee.sop.gatewaycommon.limit.LimitManager; +import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; import com.gitee.sop.gatewaycommon.manager.DefaultIPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager; +import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.manager.IPBlacklistManager; import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.manager.RouteConfigManager; import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; -import com.gitee.sop.gatewaycommon.manager.EnvGrayManager; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.result.DataNameBuilder; import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder; @@ -149,6 +150,8 @@ public class ApiConfig { */ private ZuulErrorController zuulErrorController = new ZuulErrorController(); + private ParameterFormatter zuulParametersFormatter; + // -------- fields --------- /** 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/ParameterFormatter.java new file mode 100644 index 00000000..4e51cf11 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java @@ -0,0 +1,19 @@ +package com.gitee.sop.gatewaycommon.manager; + +import com.alibaba.fastjson.JSONObject; + +/** + * 参数格式化 + * + * @author tanghc + */ +public interface ParameterFormatter { + + /** + * 参数格式化,即动态修改请求参数 + * + * @param requestParams 原始请求参数,在此基础上追加或修改参数 + * @param requestContext requestContext + */ + void format(JSONObject requestParams, T requestContext); +} 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 8f0287f6..62063af4 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 @@ -3,6 +3,7 @@ package com.gitee.sop.gatewaycommon.zuul.configuration; 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; @@ -44,6 +45,12 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return ApiConfig.getInstance().getZuulParamBuilder(); } + @Bean + @ConditionalOnMissingBean + ParameterFormatter preParamFilter(){ + return ApiConfig.getInstance().getZuulParametersFormatter(); + } + /** * 路由存储 * @return @@ -120,6 +127,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration { return new PreVersionDecisionFilter(); } + + /** * 错误处理扩展 */ diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java index 41999b66..f41f8522 100644 --- a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java @@ -1,6 +1,7 @@ package com.gitee.sop.gatewaycommon.zuul.filter; import com.gitee.sop.gatewaycommon.exception.ApiException; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; import com.gitee.sop.gatewaycommon.param.ApiParam; import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.validate.Validator; @@ -19,6 +20,9 @@ public class PreValidateFilter extends BaseZuulFilter { @Autowired private ParamBuilder paramBuilder; + @Autowired(required = false) + private ParameterFormatter parameterFormatter; + @Autowired private Validator validator; @@ -40,6 +44,10 @@ public class PreValidateFilter extends BaseZuulFilter { // 验证操作,这里有负责验证签名参数 try { validator.validate(param); + // 校验成功后进行参数转换 + if (parameterFormatter != null) { + parameterFormatter.format(param, requestContext); + } } catch (ApiException e) { log.error("验证失败,ip:{}, params:{}", param.fetchIp(), param.toJSONString(), e); throw e; diff --git a/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java new file mode 100644 index 00000000..24941c84 --- /dev/null +++ b/sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java @@ -0,0 +1,146 @@ +package com.gitee.sop.gatewaycommon.zuul.param; + +import com.gitee.sop.gatewaycommon.bean.SopConstants; +import com.gitee.sop.gatewaycommon.manager.ParameterFormatter; +import com.gitee.sop.gatewaycommon.param.ApiParam; +import com.gitee.sop.gatewaycommon.util.RequestUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import com.netflix.zuul.http.HttpServletRequestWrapper; +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; +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.Collections; +import java.util.List; +import java.util.Map; + +/** + * @author tanghc + */ +@Slf4j +public abstract class BaseParameterFormatter implements ParameterFormatter { + + private FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); + + public void formatParams(ApiParam apiParam, RequestContext requestContext) throws ZuulException { + this.format(apiParam, requestContext); + HttpServletRequest request = requestContext.getRequest(); + String contentType = request.getContentType(); + if (StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, bytes)); + } else if(StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + List list = Lists.newArrayList(); + try { + for (Map.Entry entry : apiParam.entrySet()) { + list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), SopConstants.UTF8)); + } + } catch (UnsupportedEncodingException e) { + log.error("字符集不支持", e); + } + String paramsStr = StringUtils.join(list, "&"); + byte[] data = paramsStr.getBytes(StandardCharsets.UTF_8); + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + } else if(RequestUtil.isMultipart(request)) { + FormHttpOutputMessage outputMessage = new FormHttpOutputMessage(); + try { + // 转成MultipartRequest + CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(request.getServletContext()); + request = commonsMultipartResolver.resolveMultipart(request); + // 重写新的值 + MultiValueMap builder = RequestContentDataExtractor.extract(request); + for (Map.Entry entry : apiParam.entrySet()) { + builder.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + } + MediaType mediaType = MediaType.valueOf(request.getContentType()); + // 将字段以及上传文件重写写入到流中 + formHttpMessageConverter.write(builder, mediaType, outputMessage); + // 获取新的上传文件流 + byte[] data = outputMessage.getInput(); + + requestContext.setRequest(new ChangeParamsHttpServletRequestWrapper(request, data)); + // 必须要重新指定content-type,因为此时的boundary已经发生改变 + requestContext.getZuulRequestHeaders().put("content-type", outputMessage.getHeaders().getContentType().toString()); + } catch (Exception e) { + log.error("修改上传文件请求参数失败, apiParam:{}", apiParam, e); + } + } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { + Map> newParams = Maps.newHashMap(); + for (Map.Entry entry : apiParam.entrySet()) { + newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); + } + requestContext.setRequestQueryParams(newParams); + } + } + + + 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; + + public ChangeParamsHttpServletRequestWrapper(HttpServletRequest request, byte[] data) { + super(request); + this.data = data; + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return new ServletInputStreamWrapper(data); + } + + @Override + public byte[] getContentData() { + return data; + } + + @Override + public int getContentLength() { + return data.length; + } + + @Override + public long getContentLengthLong() { + return data.length; + } + } +} diff --git a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java b/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java deleted file mode 100644 index 74b78789..00000000 --- a/sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.gitee.sop.gateway.config; - -import com.alibaba.fastjson.JSONObject; -import com.gitee.sop.gatewaycommon.param.ApiParam; -import com.gitee.sop.gatewaycommon.param.ParamNames; -import com.gitee.sop.gatewaycommon.zuul.ZuulContext; -import com.gitee.sop.gatewaycommon.zuul.filter.BaseZuulFilter; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.netflix.zuul.context.RequestContext; -import com.netflix.zuul.exception.ZuulException; -import com.netflix.zuul.http.HttpServletRequestWrapper; -import com.netflix.zuul.http.ServletInputStreamWrapper; -import org.apache.commons.lang.StringUtils; -import org.springframework.http.HttpMethod; - -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** - * @author tanghc - */ -public class PreParamFilter extends BaseZuulFilter { - @Override - protected FilterType getFilterType() { - return FilterType.PRE; - } - - @Override - protected int getFilterOrder() { - return 0; - } - - @Override - protected Object doRun(RequestContext requestContext) throws ZuulException { - ApiParam apiParam = ZuulContext.getApiParam(); - JSONObject bizContent = apiParam.getJSONObject(ParamNames.BIZ_CONTENT_NAME); - // 修改biz_content中的参数 - bizContent.put("name", "修改了111"); - apiParam.put(ParamNames.BIZ_CONTENT_NAME, bizContent.toJSONString()); - - HttpServletRequest request = requestContext.getRequest(); - String contentType = request.getContentType(); - if (StringUtils.containsIgnoreCase(contentType, "json")) { - byte[] bytes = apiParam.toJSONString().getBytes(StandardCharsets.UTF_8); - requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { - @Override - public ServletInputStream getInputStream() throws IOException { - return new ServletInputStreamWrapper(bytes); - } - - @Override - public byte[] getContentData() { - return bytes; - } - - @Override - public int getContentLength() { - return bytes.length; - } - - @Override - public long getContentLengthLong() { - return bytes.length; - } - }); - } else if(StringUtils.containsIgnoreCase(contentType, "form")) { - List list = Lists.newArrayList(); - try { - for (Map.Entry entry : apiParam.entrySet()) { - list.add(entry.getKey() + "=" + URLEncoder.encode(String.valueOf(entry.getValue()), "UTF-8")); - } - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - String paramsStr = StringUtils.join(list, "&"); - byte[] bytes = paramsStr.getBytes(StandardCharsets.UTF_8); - requestContext.setRequest(new HttpServletRequestWrapper(requestContext.getRequest()) { - @Override - public ServletInputStream getInputStream() throws IOException { - return new ServletInputStreamWrapper(bytes); - } - - @Override - public byte[] getContentData() { - return bytes; - } - - @Override - public int getContentLength() { - return bytes.length; - } - - @Override - public long getContentLengthLong() { - return bytes.length; - } - }); - } else if(HttpMethod.GET.name().equalsIgnoreCase(request.getMethod())) { - Map> newParams = Maps.newHashMap(); - for (Map.Entry entry : apiParam.entrySet()) { - newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue()))); - } - requestContext.setRequestQueryParams(newParams); - } - - return null; - } -} diff --git a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java index 68aaf5d9..d202aef6 100644 --- a/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java +++ b/sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java @@ -1,6 +1,7 @@ package com.gitee.sop.sdk.client; import com.gitee.sop.sdk.common.OpenConfig; +import com.gitee.sop.sdk.common.RequestMethod; import com.gitee.sop.sdk.common.UploadFile; import okhttp3.Cookie; import okhttp3.CookieJar; @@ -118,7 +119,7 @@ public class OpenHttp { * @return * @throws IOException */ - public String request(String url, Map form, Map header, HTTPMethod method) throws IOException { + public String request(String url, Map form, Map header, RequestMethod method) throws IOException { Request.Builder requestBuilder = buildRequestBuilder(url, form, method); // 添加header addHeader(requestBuilder, header); @@ -134,7 +135,7 @@ public class OpenHttp { } } - public static Request.Builder buildRequestBuilder(String url, Map form, HTTPMethod method) { + public static Request.Builder buildRequestBuilder(String url, Map form, RequestMethod method) { switch (method) { case GET: return new Request.Builder() @@ -241,22 +242,4 @@ public class OpenHttp { this.httpClient = httpClient; } - public enum HTTPMethod { - GET, - POST, - PUT, - HEAD, - DELETE; - - private HTTPMethod() { - } - - public String value() { - return this.name(); - } - - public static HTTPMethod fromValue(String v) { - return valueOf(v.toUpperCase()); - } - } } diff --git a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java index 16a2b18c..3ae9c3b3 100644 --- a/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java +++ b/sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.java @@ -100,11 +100,9 @@ public class SdkTest extends TestCase { if (response.isSuccess()) { List responseFiles = response.getFiles(); System.out.println("您上传的文件信息:"); - responseFiles.stream().forEach(file->{ - System.out.println(file); - }); + responseFiles.forEach(System.out::println); } else { - System.out.println("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg()); + System.out.println(JSON.toJSONString(response)); } System.out.println("--------------------"); }