如何使用Spring Webflux读取请求正文

4 project-reactor spring-webflux spring-cloud-gateway

我正在使用Spring 5,Netty和Spring webflux开发API网关。有时我希望该请求由网关停止,但我也想读取请求的主体以将其记录下来,例如,将错误返回给客户端。

我尝试通过订阅主体在WebFilter中执行此操作。

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    if (enabled) {
        logger.debug("gateway is enabled. The Request is routed.");
        return chain.filter(exchange);
    } else {
        logger.debug("gateway is disabled. A 404 error is returned.");

        exchange.getRequest().getBody().subscribe();
        exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().allocateBuffer(0)));
    }
}
Run Code Online (Sandbox Code Playgroud)

当我这样做时,当身体的内容很小时,它就会起作用。但是,当我有一个很大的跳闸时,只读取磁通量的第一个元素,因此无法获得整个人体。任何想法如何做到这一点?

Bri*_*zel 5

这里的问题是您正在过滤器中手动预订,这意味着您正在断开请求与其他管道的连接。调用subscribe()会为您提供Disposable帮助您管理基础的Subscription

因此,您需要将整个过程作为单个管道进行连接,有点像:

Flux<DataBuffer> requestBody = exchange.getRequest().getBody();
// decode the request body as a Mono or a Flux
Mono<String> decodedBody = decodeBody(requestBody); 
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return decodedBody.doOnNext(s -> logger.info(s))
                  .then(exchange.getResponse().setComplete());
Run Code Online (Sandbox Code Playgroud)

请注意,将整个请求正文解码为一种Mono手段,您的网关将不得不在内存中缓冲整个请求正文。

DataBuffer是故意的低级别类型。如果您想将其解码decodeBody为String (即实现示例方法),则可以使用DecoderSpring 中的各种实现之一,例如StringDecoder

现在,由于这是一个相当大且复杂的空间,您可以使用和/或查看Spring Cloud Gateway,它不仅可以做到这一点,而且还可以做更多的事情。


ben*_*reg 5

1.在post路由中添加“ readBody() ”:

builder.routes()
.route("get_route", r -> r.path("/**")
    .and().method("GET")
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))
.route("post_route", r -> r.path("/**")
    .and().method("POST")
    .and().readBody(String.class, requestBody -> {return true;})
    .filters(f -> f.filter(myFilter))
    .uri(myUrl))
Run Code Online (Sandbox Code Playgroud)

2.然后您可以在过滤器中获取正文字符串:

String body = exchange.getAttribute("cachedRequestBodyObject");
Run Code Online (Sandbox Code Playgroud)

好处:

  1. 没有阻塞。

  2. 无需重新填充身体以进行进一步处理。

适用于 Spring Boot 2.0.6.RELEASE + Sring Cloud Finchley.SR2 + Spring Cloud Gateway。