当前位置: 首页 > 知识库问答 >
问题:

WebClient--如何获得请求主体?

狄冥夜
2023-03-14
WebClient.builder()
    .baseUrl(properties.getEndpoint())
    .filter((request, next) -> {
        // logging
        request.body()
    })
    .build();

如何将BodyInserter转换为请求正文的String表示形式?或者,如何正确地记录整个请求/响应,同时能够在其中散列潜在的凭据?

共有1个答案

姬博瀚
2023-03-14

您可以围绕JSON编码器创建自己的包装器/代理类,并在序列化的主体发送到Intertube之前拦截它。

这篇博文展示了如何记录WebClient请求和响应的JSON负载

具体来说,您将扩展Jackson2JsonEncoderencodeValue方法(如果是流数据,则为encodeValues)。然后,您可以对这些数据做您想做的事情,比如日志记录等,您甚至可以根据环境/配置文件有条件地这样做

 CustomBodyLoggingEncoder bodyLoggingEncoder = new CustomBodyLoggingEncoder();
 WebClient.builder()
          .codecs(clientDefaultCodecsConfigurer -> {
             clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonEncoder(bodyLoggingEncoder);
             clientDefaultCodecsConfigurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.APPLICATION_JSON));
          })
          ...

下面是一个匆忙的例子,它应用了同样的原理,但对于解码器来说:

public class LoggingJsonDecoder extends Jackson2JsonDecoder {
    private final Consumer<byte[]> payloadConsumer;

    public LoggingJsonEncoder(final Consumer<byte[]> payloadConsumer) {
        this.payloadConsumer = payloadConsumer;
    }

    @Override
    public Mono<Object> decodeToMono(final Publisher<DataBuffer> input, final ResolvableType elementType, final MimeType mimeType, final Map<String, Object> hints) {
        // Buffer for bytes from each published DataBuffer
        final ByteArrayOutputStream payload = new ByteArrayOutputStream();

        // Augment the Flux, and intercept each group of bytes buffered
        final Flux<DataBuffer> interceptor = Flux.from(input)
                                                 .doOnNext(buffer -> bufferBytes(payload, buffer))
                                                 .doOnComplete(() -> payloadConsumer.accept(payload.toByteArray()));

        // Return the original method, giving our augmented Publisher
        return super.decodeToMono(interceptor, elementType, mimeType, hints);
    }

    private void bufferBytes(final ByteArrayOutputStream bao, final DataBuffer buffer) {
        try {
            bao.write(ByteUtils.extractBytesAndReset(buffer));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

您可以在WebClient上使用codecs构建器方法配置编码器。当然,上述方法只在假设数据被反序列化为单声道的情况下有效。但如果需要,重写其他方法。另外,我只是在那里stdout'生成的JSON,但是您可以传入使用者 或其他东西,例如让解码器发送字符串,或者只是从那里记录;由你决定。

警告一下,在当前的形式下,这将使您的内存使用量增加一倍,因为它缓冲了整个响应。如果您可以将该字节数据发送到另一个进程/线程,以便立即写入日志文件或某个输出流(甚至是流量),则可以避免在内存中缓冲整个有效负载。

 类似资料:
  • 我正在使用Spring5WebClient从RESTAPI重复获取运行进程的某些状态。 在这里的帮助下,我现在找到了这个解决方案: 在这种情况下,get请求以非常高的速率触发。什么是正确的方法来限制请求速率,让我们说每秒1个请求? 我尝试使用,但这只会延迟结果,而不会延迟请求本身。

  • 问题内容: 我是Go的新手,但到目前为止,我非常喜欢它。 我有一个我不知道的问题。我正在将API从Node迁移到Go,并且有此日志必须捕获POST 原样 并将其保存到Postgresql数据库的type列中。 这意味着我不能使用或预定的任何东西。 POST是用body raw制作的,如下所示: 在Node + Hapi上非常简单: 然后我可以从访问JSON 。 我正在将Go与Echo一起使用,所以

  • Spring留档声明,即使要执行同步超文本传输协议调用,我们也必须从RestTemboard切换到。 目前,我有以下代码: 当然,我可以在这里使用CountdownLatch,但它看起来像是API滥用。 如何执行同步请求?

  • 我正在尝试使用<code>网络客户端 谢谢 -斯里尼

  • 我的目标是从Spring WebClient请求中获取HttpStatus。请求的所有其他信息都不相关。