gateway网关获取请求body为空
最近在项目中,有一个业务需要就是对指定接口传的参数与redis缓存中的值做比较,我与网上大多数一样都是这样直接获取
@Component
public class testGatewayFilterFactory extends AbstractGatewayFilterFactory {
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
//从请求里获取请求体
String requestBodyStr = resolveBodyFromRequest(request);
try {
//验证请求body中是否含有某个字段
testDao.containsStr(requestBodyStr);
} catch (Exception e) {
//异常信息返回
e.printStackTrace();
ServerHttpResponse response = exchange.getResponse();
JSONObject message = new JSONObject();
message.put("STATUS", -1);
message.put("DATA", e.getMessage());
byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = response.bufferFactory().wrap(bits);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
// 修改路径
String newPath ="/test" + request.getPath();
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
//放行
return chain.filter(exchange.mutate()
.request(newRequest).build());
};
}
/**
* 从Flux<DataBuffer>中获取字符串的方法
* @return 请求体
*/
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//获取请求体
Flux<DataBuffer> body = serverHttpRequest.getBody();
AtomicReference<String> bodyRef = new AtomicReference<>();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
});
//获取request body
return bodyRef.get();
}
}
但是获取的body一直是空的。网上说是要先通过全局过滤器先把body缓存起来,之后后面的过滤器中再使用exchange.getRequest().getBody()来获取body时,就能获取到了。但是我testGatewayFilterFactory这个过滤器设置的级别order是0,级别在我设置的过滤器中是最高的,指定方法第一个进的filter也是它,为什么还要缓存起来呢。后来在自己定义的一个全局过滤器打断点,发现请求方法进入了testGatewayFilterFactory局部过滤器之后没执行完,又到了全局过滤器,这时候我觉得应该是要将body缓存起来,试了一下还真的可以。只是现在还不知道具体的原因,希望有小伙伴能告诉我。不过获取body为空的问题是解决了。
主要就是在增加一个全局过滤器,把级别设置为最高,把body缓存好。上代码网上也有很多
@Component
public class testBodyGlobalFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (exchange.getRequest().getHeaders().getContentType() == null) {
return chain.filter(exchange);
} else {
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
DataBufferUtils.retain(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
return chain.filter(exchange.mutate().request(mutatedRequest).build());
});
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
Ordered.HIGHEST_PRECEDENCE就是最高级别的,所有请求第一个走的都是这个过滤器,加了这个过滤器后,testGatewayFilterFactory 这个局部过滤器就可以获取到body的数据了。