【问题标题】:How to read the request body with spring webflux如何使用 spring webflux 读取请求正文
【发布时间】:2018-10-07 04:23:22
【问题描述】:

我正在使用 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)));
    }
}

当我这样做时,它在正文内容很小的情况下起作用。但是当我有一个大婴儿时,只读取通量的第一个元素,所以我不能拥有整个身体。知道怎么做吗?

【问题讨论】:

    标签: spring-webflux project-reactor spring-cloud-gateway


    【解决方案1】:

    这里的问题是您在过滤器中手动订阅,这意味着您正在断开对请求的读取与管道的其余部分的连接。调用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());
    

    请注意,将整个请求正文解码为 Mono 意味着您的网关必须在内存中缓冲整个请求正文。

    DataBuffer 故意是低级类型。如果您想将其解码(即实现示例 decodeBodymethod)作为字符串,您可以使用 Spring 中的各种 Decoder 实现之一,例如 StringDecoder

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

    【讨论】:

      【解决方案2】:

      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))
      

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

      String body = exchange.getAttribute("cachedRequestBodyObject");
      

      优点:

      1. 无阻塞。

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

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

      【讨论】:

      • 不再与 Greenwhich 一起使用 - 由于某种原因,您会收到由 org.springframework.web.reactive.resource.ResourceWebHandler.lambda$handle$0(ResourceWebHandler.java) 中收到的空单声道引起的异常:325)。
      猜你喜欢
      • 2019-01-17
      • 1970-01-01
      • 1970-01-01
      • 2019-07-23
      • 2020-08-25
      • 2020-10-17
      • 2021-01-28
      • 1970-01-01
      • 2019-10-06
      相关资源
      最近更新 更多