mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
动态修改请求参数
This commit is contained in:
@@ -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<RequestContext> zuulParametersFormatter;
|
||||
|
||||
// -------- 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.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<RequestContext> preParamFilter(){
|
||||
return ApiConfig.getInstance().getZuulParametersFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由存储
|
||||
* @return
|
||||
@@ -120,6 +127,8 @@ public class BaseZuulConfiguration extends AbstractConfiguration {
|
||||
return new PreVersionDecisionFilter();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 错误处理扩展
|
||||
*/
|
||||
|
@@ -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<RequestContext> paramBuilder;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ParameterFormatter<RequestContext> 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;
|
||||
|
@@ -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;
|
||||
|
||||
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<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);
|
||||
// 添加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) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -100,11 +100,9 @@ public class SdkTest extends TestCase {
|
||||
if (response.isSuccess()) {
|
||||
List<DemoFileUploadResponse.FileMeta> 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("--------------------");
|
||||
}
|
||||
|
Reference in New Issue
Block a user