gateway动态修改参数

1.x
tanghc 5 years ago
parent 5a56b5f98b
commit de8ad5ffaa
  1. 68
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/ServerWebExchangeUtil.java
  2. 65
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/common/SopServerHttpRequestDecorator.java
  3. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/LimitFilter.java
  4. 14
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/Orders.java
  5. 25
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ParameterFormatterFilter.java
  6. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/gateway/filter/ValidateFilter.java
  7. 3
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/BaseZuulFilter.java
  8. 2
      sop-common/sop-gateway-common/src/main/java/com/gitee/sop/gatewaycommon/zuul/filter/PreVersionDecisionFilter.java

@ -3,17 +3,23 @@ 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.SopServerHttpRequestDecorator;
import com.gitee.sop.gatewaycommon.param.ApiParam;
import com.gitee.sop.gatewaycommon.util.RequestUtil;
import io.netty.buffer.ByteBufAllocator;
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.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
@ -126,16 +132,70 @@ public class ServerWebExchangeUtil {
}
/**
* 修改请求参数
* 修改请求参数参考自https://blog.csdn.net/fuck487/article/details/85166162
* @param exchange ServerWebExchange
* @param apiParam 请求参数
* @param consumer 执行参数更改
* @param paramsConsumer 执行参数更改
* @param headerConsumer header更改
* @param <T> 参数类型
* @return 返回新的ServerWebExchange
* @return 返回新的ServerWebExchange参数没有被修改则返回null
*/
public static <T extends Map<String, Object>> ServerWebExchange format(ServerWebExchange exchange, T apiParam, Consumer<T> consumer) {
public static <T extends Map<String, Object>> ServerWebExchange format(
ServerWebExchange exchange
, T apiParam
, Consumer<T> paramsConsumer
, Consumer<HttpHeaders> headerConsumer
) {
ServerHttpRequest serverHttpRequest = exchange.getRequest();
if (serverHttpRequest.getMethod() == HttpMethod.GET) {
paramsConsumer.accept(apiParam);
} else {
MediaType mediaType = serverHttpRequest.getHeaders().getContentType();
if (mediaType == null) {
return null;
}
paramsConsumer.accept(apiParam);
String contentType = mediaType.toString().toLowerCase();
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();
} else {
}
}
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;
}
}

@ -0,0 +1,65 @@
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.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import reactor.core.publisher.Flux;
/**
* @author tanghc
*/
public class SopServerHttpRequestDecorator extends ServerHttpRequestDecorator {
private Flux<DataBuffer> bodyData;
private HttpHeaders httpHeaders;
public SopServerHttpRequestDecorator(ServerHttpRequest delegate, byte[] bodyData, HttpHeaders httpHeaders) {
super(delegate);
if (httpHeaders == null) {
throw new IllegalArgumentException("httpHeaders can not be null.");
}
if (bodyData == null) {
throw new IllegalArgumentException("bodyData can not be null.");
}
// 由于请求体已改变,这里要重新设置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);
}
/**
* 字符串转DataBuffer
* @param bytes 请求体
* @return 返回buffer
*/
private static Flux<DataBuffer> stringBuffer(byte[] bytes) {
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return Flux.just(buffer);
}
private SopServerHttpRequestDecorator(ServerHttpRequest delegate) {
super(delegate);
}
@Override
public Flux<DataBuffer> getBody() {
return bodyData == null ? super.getBody() : bodyData;
}
@Override
public HttpHeaders getHeaders() {
return httpHeaders == null ? super.getHeaders() : httpHeaders;
}
}

@ -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) {

@ -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;
}

@ -4,7 +4,6 @@ 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 com.gitee.sop.gatewaycommon.zuul.ZuulContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
@ -13,6 +12,8 @@ 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
*/
@ -24,18 +25,30 @@ public class ParameterFormatterFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ApiParam apiParam = ZuulContext.getApiParam();
ApiParam apiParam = ServerWebExchangeUtil.getApiParam(exchange);
if (apiParam == null) {
return chain.filter(exchange);
}
// 校验成功后进行参数转换
if (sopParameterFormatter != null) {
ServerWebExchange formatExchange = ServerWebExchangeUtil.format(exchange, apiParam, sopParameterFormatter::format);
ServerWebExchange serverWebExchange = ServerWebExchangeUtil.addHeaders(formatExchange, httpHeaders -> httpHeaders.add(ParamNames.HEADER_VERSION_NAME, apiParam.fetchVersion()));
return chain.filter(serverWebExchange);
ServerWebExchange formatExchange = ServerWebExchangeUtil.format(
exchange
, apiParam
, sopParameterFormatter::format
, httpHeaders -> {
httpHeaders.remove(ParamNames.HEADER_VERSION_NAME);
httpHeaders.add(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 0;
return PARAMETER_FORMATTER_FILTER_ORDER;
}
}

@ -43,6 +43,6 @@ public class ValidateFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 最优先执行
return Orders.VALIDATE_ORDER;
return Orders.VALIDATE_FILTER_ORDER;
}
}

@ -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;
/**

@ -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

Loading…
Cancel
Save