动态修改请求参数

1.x
tanghc 5 years ago
parent 7c47af3913
commit 36b5123ad7
  1. 7
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/bean/ApiConfig.java
  2. 19
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/manager/ParameterFormatter.java
  3. 9
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/configuration/BaseZuulConfiguration.java
  4. 8
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreValidateFilter.java
  5. 146
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/param/BaseParameterFormatter.java
  6. 116
      sop-gateway/src/main/java/com/gitee/sop/gateway/config/PreParamFilter.java
  7. 23
      sop-sdk/sdk-java/src/main/java/com/gitee/sop/sdk/client/OpenHttp.java
  8. 6
      sop-sdk/sdk-java/src/test/java/com/gitee/sop/sdk/SdkTest.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.gateway.result.GatewayResultExecutor;
import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager; import com.gitee.sop.gatewaycommon.limit.DefaultLimitManager;
import com.gitee.sop.gatewaycommon.limit.LimitManager; 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.DefaultIPBlacklistManager;
import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.DefaultIsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultLimitConfigManager;
import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager; import com.gitee.sop.gatewaycommon.manager.DefaultRouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.DefaultServiceErrorManager; 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.IPBlacklistManager;
import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager; import com.gitee.sop.gatewaycommon.manager.IsvRoutePermissionManager;
import com.gitee.sop.gatewaycommon.manager.LimitConfigManager; 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.RouteConfigManager;
import com.gitee.sop.gatewaycommon.manager.ServiceErrorManager; 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.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.result.DataNameBuilder; import com.gitee.sop.gatewaycommon.result.DataNameBuilder;
import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder; import com.gitee.sop.gatewaycommon.result.DefaultDataNameBuilder;
@ -149,6 +150,8 @@ public class ApiConfig {
*/ */
private ZuulErrorController zuulErrorController = new ZuulErrorController(); private ZuulErrorController zuulErrorController = new ZuulErrorController();
private ParameterFormatter<RequestContext> zuulParametersFormatter;
// -------- fields --------- // -------- fields ---------
/** /**

@ -0,0 +1,19 @@
package com.gitee.sop.gatewaycommon.manager;
import com.alibaba.fastjson.JSONObject;
/**
* 参数格式化
*
* @author tanghc
*/
public interface ParameterFormatter<T> {
/**
* 参数格式化即动态修改请求参数
*
* @param requestParams 原始请求参数在此基础上追加或修改参数
* @param requestContext requestContext
*/
void format(JSONObject requestParams, T requestContext);
}

@ -3,6 +3,7 @@ package com.gitee.sop.gatewaycommon.zuul.configuration;
import com.gitee.sop.gatewaycommon.bean.ApiConfig; import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ApiContext; import com.gitee.sop.gatewaycommon.bean.ApiContext;
import com.gitee.sop.gatewaycommon.manager.AbstractConfiguration; 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.manager.RouteRepositoryContext;
import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter; import com.gitee.sop.gatewaycommon.zuul.filter.ErrorFilter;
@ -44,6 +45,12 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return ApiConfig.getInstance().getZuulParamBuilder(); return ApiConfig.getInstance().getZuulParamBuilder();
} }
@Bean
@ConditionalOnMissingBean
ParameterFormatter<RequestContext> preParamFilter(){
return ApiConfig.getInstance().getZuulParametersFormatter();
}
/** /**
* 路由存储 * 路由存储
* @return * @return
@ -120,6 +127,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
return new PreVersionDecisionFilter(); return new PreVersionDecisionFilter();
} }
/** /**
* 错误处理扩展 * 错误处理扩展
*/ */

@ -1,6 +1,7 @@
package com.gitee.sop.gatewaycommon.zuul.filter; package com.gitee.sop.gatewaycommon.zuul.filter;
import com.gitee.sop.gatewaycommon.exception.ApiException; 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.ApiParam;
import com.gitee.sop.gatewaycommon.param.ParamBuilder; import com.gitee.sop.gatewaycommon.param.ParamBuilder;
import com.gitee.sop.gatewaycommon.validate.Validator; import com.gitee.sop.gatewaycommon.validate.Validator;
@ -19,6 +20,9 @@ public class PreValidateFilter extends BaseZuulFilter {
@Autowired @Autowired
private ParamBuilder<RequestContext> paramBuilder; private ParamBuilder<RequestContext> paramBuilder;
@Autowired(required = false)
private ParameterFormatter<RequestContext> parameterFormatter;
@Autowired @Autowired
private Validator validator; private Validator validator;
@ -40,6 +44,10 @@ public class PreValidateFilter extends BaseZuulFilter {
// 验证操作,这里有负责验证签名参数 // 验证操作,这里有负责验证签名参数
try { try {
validator.validate(param); validator.validate(param);
// 校验成功后进行参数转换
if (parameterFormatter != null) {
parameterFormatter.format(param, requestContext);
}
} catch (ApiException e) { } catch (ApiException e) {
log.error("验证失败,ip:{}, params:{}", param.fetchIp(), param.toJSONString(), e); log.error("验证失败,ip:{}, params:{}", param.fetchIp(), param.toJSONString(), e);
throw e; throw e;

@ -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<RequestContext> {
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<String> list = Lists.newArrayList();
try {
for (Map.Entry<String, Object> 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<String, Object> builder = RequestContentDataExtractor.extract(request);
for (Map.Entry<String, Object> 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<String, List<String>> newParams = Maps.newHashMap();
for (Map.Entry<String, Object> 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;
}
}
}

@ -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<String> list = Lists.newArrayList();
try {
for (Map.Entry<String, Object> 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<String, List<String>> newParams = Maps.newHashMap();
for (Map.Entry<String, Object> entry : apiParam.entrySet()) {
newParams.put(entry.getKey(), Collections.singletonList(String.valueOf(entry.getValue())));
}
requestContext.setRequestQueryParams(newParams);
}
return null;
}
}

@ -1,6 +1,7 @@
package com.gitee.sop.sdk.client; package com.gitee.sop.sdk.client;
import com.gitee.sop.sdk.common.OpenConfig; import com.gitee.sop.sdk.common.OpenConfig;
import com.gitee.sop.sdk.common.RequestMethod;
import com.gitee.sop.sdk.common.UploadFile; import com.gitee.sop.sdk.common.UploadFile;
import okhttp3.Cookie; import okhttp3.Cookie;
import okhttp3.CookieJar; import okhttp3.CookieJar;
@ -118,7 +119,7 @@ public class OpenHttp {
* @return * @return
* @throws IOException * @throws IOException
*/ */
public String request(String url, Map<String, String> form, Map<String, String> header, HTTPMethod method) throws IOException { public String request(String url, Map<String, String> form, Map<String, String> header, RequestMethod method) throws IOException {
Request.Builder requestBuilder = buildRequestBuilder(url, form, method); Request.Builder requestBuilder = buildRequestBuilder(url, form, method);
// 添加header // 添加header
addHeader(requestBuilder, header); addHeader(requestBuilder, header);
@ -134,7 +135,7 @@ public class OpenHttp {
} }
} }
public static Request.Builder buildRequestBuilder(String url, Map<String, String> form, HTTPMethod method) { public static Request.Builder buildRequestBuilder(String url, Map<String, String> form, RequestMethod method) {
switch (method) { switch (method) {
case GET: case GET:
return new Request.Builder() return new Request.Builder()
@ -241,22 +242,4 @@ public class OpenHttp {
this.httpClient = httpClient; 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());
}
}
} }

@ -100,11 +100,9 @@ public class SdkTest extends TestCase {
if (response.isSuccess()) { if (response.isSuccess()) {
List<DemoFileUploadResponse.FileMeta> responseFiles = response.getFiles(); List<DemoFileUploadResponse.FileMeta> responseFiles = response.getFiles();
System.out.println("您上传的文件信息:"); System.out.println("您上传的文件信息:");
responseFiles.stream().forEach(file->{ responseFiles.forEach(System.out::println);
System.out.println(file);
});
} else { } else {
System.out.println("errorCode:" + response.getCode() + ",errorMsg:" + response.getMsg()); System.out.println(JSON.toJSONString(response));
} }
System.out.println("--------------------"); System.out.println("--------------------");
} }

Loading…
Cancel
Save