我们在使用SpringCloud-gateway作为网关转发的时候,当post请求参数过程,刚好需要针对post请求体做相应的操作时候的,会发现每次获取的请求参数获取不全的问题,以下解决方法,来自于百度总结,实战可用;
@Component
public class DefaulFilter implements GlobalFilter, Ordered {
public final static String REDIS_KEY_ACCESS_TOKEN_PLATFORM = "PLATFORM_ACCESS_TOKEN#";
@Value(value = "${platform.publicKey}")
private String publicKey;
@Value(value = "${platform.privateKey}")
private String privateKey;
@Autowired
@Qualifier(value = "excludeRequestMap")
private Map<String, String> excludeRequestMap;
private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();
@Override
public int getOrder() {
return -2;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest serverHttpRequest= exchange.getRequest();
// 符合条件请求直接放行:1.swagger文档请求接口 2.相关的登录请求接口
if (excludeRequestMap.containsKey(serverHttpRequest.getURI().getPath())
|| HttpMethod.GET.equals(serverHttpRequest.getMethod())) {
return chain.filter(exchange.mutate().request(exchange.getRequest()).build());
}
//判断是否为post请求
if (HttpMethod.POST.equals(serverHttpRequest.getMethod())) {
return processRequest(exchange, chain);
}else if (HttpMethod.GET.equals(serverHttpRequest.getMethod())) {
//1 判断是否为get请求
return chain.filter(exchange);
}
return chain.filter(exchange);
}
private Mono<Void> processRequest(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerRequest serverRequest = new DefaultServerRequest(exchange, messageReaders);
DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
Mono<String> rawBody = serverRequest.bodyToMono(String.class).map(s -> s);
BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromPublisher(rawBody, String.class);
//从head中获取敏感信息--机密后的json字符串
HttpHeaders headers = exchange.getRequest().getHeaders();
String platformEnExchangeInfo = headers.getFirst(LogFilterConstants.PLATFORM_EXCHANGE_INFO);
SensitiveInfoView sensitiveInfoView=new SensitiveInfoView();
//通过私钥解密获取解密后敏感信息-加密信息不为空
if(StringUtils.isNotBlank(platformEnExchangeInfo)) {
try {
PrivateKey privateKeyEntity = RsaUtils.getPrivateKey(privateKey);
String platformDeExchangeInfo = RsaUtils.decrypt(platformEnExchangeInfo, privateKeyEntity);
//转换成json对象
JSONObject jsonObject = JSONObject.parseObject(platformDeExchangeInfo);
sensitiveInfoView = JSON.toJavaObject(jsonObject, SensitiveInfoView.class);
} catch (Exception e) {
e.printStackTrace();
}
}
//把用户信息压入token中
Map<String, Object> claimsMap = new HashMap<>();
// claimsMap.put(LogFilterConstants.SENSITIVE_INFO_KEY, sensitiveInfoView);
claimsMap.put("CLAIM_NAME_ID_NO",sensitiveInfoView.getIdNo());
String newToken = JwtUtils.createAccessToken(sensitiveInfoView.getMobileNumber(),claimsMap, 1000);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
Flux<DataBuffer> body = outputMessage.getBody();
DataBufferHolder holder = new DataBufferHolder();
body.subscribe(dataBuffer -> {
int len = dataBuffer.readableByteCount();
holder.length = len;
byte[] bytes = new byte[len];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
//修改请求体参数值
String text = new String(bytes, StandardCharsets.UTF_8);
JSONObject newBodyStr = JSONObject.parseObject(text);
newBodyStr.put("token", newToken);
text=newBodyStr.toJSONString();
DataBuffer data = bufferFactory.allocateBuffer();
data.write(text.getBytes(StandardCharsets.UTF_8));
holder.dataBuffer = data;
});
ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
//由于修改了请求体的body,导致content-length长度不确定,因此使用分块编码
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
return Flux.just(holder.dataBuffer);
}
};
return chain.filter(exchange.mutate().request(requestDecorator).build());
}));
}
private class DataBufferHolder {
DataBuffer dataBuffer;
int length;
}
}