从Spring Cloud Gateway过滤器中获取请求体的最优方案

在spring cloud gateway出现这个问题的时候我们第一反应应该很简单,但是真正实现的时候却有点困难。我看了很多相关的文档,感觉太多都不清晰而且解决不了问题。下面我就把我的方便理解的解决方案写下来。

1. 先重写请求体(过滤器优先级一定要在要获取body之前执行)

这个全局过滤器的目的就是把原有的request请求中的body内容读出来(原有的body都是以流的形式被传递),并且使用ServerHttpRequestDecorator这个请求装饰器对request进行包装,重写getBody方法,并把包装后的请求放到过滤器链中传递下去。可以满足多次获取请求。

// 重写请求体
@Component
public class GetBodyGlobalFilter implements Ordered, GlobalFilter {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (exchange.getRequest().getHeaders().getContentType() == null &&  !HttpMethod.POST.name().equalsIgnoreCase(method)) {
            return chain.filter(exchange);
        } else {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        DataBufferUtils.retain(dataBuffer);
                        Flux cachedFlux = Flux
                                .defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest).build());
                    });
        }
    }

@Override
public int getOrder() {
    return -2;
    }
}

2.写出具体的实现逻辑,及获取请求体

// 过滤器请求逻辑
@Component
public class GatewayGlobalFilter implements Ordered, GlobalFilter {

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest httpRequest = exchange.getRequest();
		// 获取请求体
        Flux body = httpRequest.getBody();
        AtomicReference bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
		String body = bodyRef.get();
		// 打印请求体
		System.out.print(body);
		return chain.filter(exchange);
    }

	@Override
	public int getOrder() {
		return -1;
	}
}

经过多方面的查看资料得出以上两个步骤就能完美的解决gateway过滤器中获取请求体的方案。

总结:先把请求体从流的方式读取出来,然后再往下进行传递,避免在处理业务的时候出现请求题为空的情况。

你可能感兴趣的:(gateway,java,servlet,maven,spring)