且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

WebClient-如何获取请求正文?

更新时间:2023-01-03 18:28:38

您可以围绕JSON编码器创建自己的包装器/代理类,并在序列化后的正文被发送到内部管道之前将其拦截。

blog post显示如何记录WebClient请求和响应的JSON负载

具体地说,您将扩展Jackson2JsonEncoderencodeValue方法(如果是流数据,则encodeValues)。然后,您可以随心所欲地处理这些数据,如日志记录等。您甚至可以根据环境/配置文件有条件地执行此操作

此自定义日志编码器可以在创建WebClient时由编解码器指定:

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

更新2020/7/3:

这里是一个匆忙的例子,应用了相同的原则,但对于解码器:

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生成器方法将其与编码器一起配置。 当然,上面的方法只有在您的数据被反序列化为Mono的情况下才有效。但如果需要,可以覆盖其他方法。另外,我只是在那里标准输出结果JSON,但是您可以传递一个Consumer<String>或其他东西,让解码器将字符串发送到,或者只是从那里记录;由您决定。 警告一句,在当前形式下,这将使您的内存使用量翻倍,因为它缓冲了整个响应。如果您可以立即将该字节数据发送到另一个进程/线程以写入日志文件或某个输出流(甚至是Flux),则可以避免在内存中缓冲整个有效负载。