mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-12 07:02:14 +08:00
gateway动态修改参数
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user