【问题标题】:How to log request body in spring Webflux Java如何在 Spring Webflux Java 中记录请求正文
【发布时间】:2020-08-25 15:37:23
【问题描述】:

我在 POST 请求中接收到一些 XML 有效负载,并希望看到收到的有效负载以进行调试。

下面(我的自定义 WebFilter)代码按预期记录 URI 和请求标头,但不记录请求正文/有效负载,我的反应代码一定有问题 -

       final ServerHttpRequest request = exchange.getRequest();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        LOGGER.info("Request: uri={}", request.getURI());
        LOGGER.info("Request: headers={}", request.getHeaders().entrySet());
        request.getBody().doOnNext(dataBuffer -> {
            try {
                Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
                String body = new String(baos.toByteArray());
                LOGGER.info("Request: payload={}", body);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

我查看了 Brian 对下面帖子的回复并关注了它,但由于没有代码,我可能犯了一些愚蠢的错误

How to log request and response bodies in Spring WebFlux

更新代码

@Configuration
public class RequestFilter implements WebFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequestFilter.class);

    @Override
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public Mono<Void> filter(ServerWebExchange serverWebExchange,
                             WebFilterChain webFilterChain) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        serverWebExchange.getRequest().getBody().doOnNext(dataBuffer -> {
            try {
                Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
                String body = new String(baos.toByteArray());
                LOGGER.info("Request: payload={}", body);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    baos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        return webFilterChain.filter(serverWebExchange);
    }
}

【问题讨论】:

  • 你在这里打破链request.getBody().doOnNext( ...
  • @ThomasAndolf - 你的意思是我需要在 doOn 之前对其进行平面映射?谢谢!
  • 不,我的意思是您似乎忽略了返回值stackoverflow.com/a/61541336/1840146
  • 所以如果我 doOnNext().subscribe() 我得到了所需的请求正文,但是就像你在上面提到的答案中解释的那样,我没有可用的数据供进一步使用。我已经多次浏览了您的帖子,但找不到放置“返回 Mono.empty()”的正确位置。谢谢!
  • 好吧,你显然以前从未使用过 webflux。这不是命令式编程。您需要始终保持联系,您不能只写request.getBody().doOnNext( ... 而忽略响应。请制作一个可重复的小示例,以便我了解更大的图景。你的小代码 sn -p 不够用。

标签: java spring-boot spring-webflux project-reactor


【解决方案1】:

除了将尸体提取到错误的位置之外,您做的部分正确。您必须在 ServerHttpRequestDecorator 实现中执行此操作,并将其插入到 WebFilter 实现中。

public class RequestLoggingDecorator extends ServerHttpRequestDecorator {

  private static final Logger LOGGER = LoggerFactory.getLogger(RequestLoggingDecorator.class);

  public RequestLoggingDecorator(ServerHttpRequest delegate) {
    super(delegate);
  }

  @Override
  public Flux<DataBuffer> getBody() {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    return super.getBody().doOnNext(dataBuffer -> {
      try {
        Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
        String body = new String(baos.toByteArray(), StandardCharsets.UTF_8);
        LOGGER.info("Request: payload={}", body);
      } catch (IOException e) {
        e.printStackTrace();
      } finally {
        try {
          baos.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    });
  }
}

然后您可以在WebFilter 实现中配置它,如下所示:

@Configuration
public class RequestLoggingFilter implements WebFilter {
  @Override
  public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
    ServerWebExchangeDecorator decorator =
        new ServerWebExchangeDecorator(serverWebExchange) {
          @Override
          public ServerHttpRequest getRequest() {
            return new RequestLoggingDecorator(serverWebExchange.getRequest());
          }
        };

    return webFilterChain.filter(decorator);
  }
}

这应该在每个传入的 Http 请求中记录您的请求正文。

【讨论】:

  • 如何在不使用 @Configuration 注释和自动配置的情况下以编程方式将这个 WebFilter 连接到 WebClient.Builder 中?
猜你喜欢
  • 2017-12-27
  • 2019-10-02
  • 2018-10-07
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 2019-01-17
  • 1970-01-01
  • 2018-11-03
相关资源
最近更新 更多