我已经开始使用WebClient,并且正在添加请求/响应的日志记录,并且在构造WebClient时正在使用过滤器方法:
WebClient.builder()
.baseUrl(properties.getEndpoint())
.filter((request, next) -> {
// logging
request.body()
})
.build();
我可以访问url,http方法,标头,但是我无法获取原始请求主体,因为请求的主体是body()
请求的方法返回了BodyInserter
(BodyInserter<?, ? super ClientHttpRequest> body()
。>
如何将BodyInserter
转换为请求正文的String
表示形式?另外,如何在正确记录整个请求/响应的同时还能够对其中的潜在凭据进行哈希处理?
答案 0 :(得分:1)
您可以围绕JSON编码器创建自己的wrapper / proxy类,并在将序列化的正文发送到插管之前对其进行拦截。
此blog post显示了如何记录WebClient请求和响应的JSON有效负载
具体来说,您将扩展encodeValue
的{{1}}方法(或在流数据的情况下为encodeValues
)。然后,您可以根据需要处理这些数据,例如日志记录等。甚至可以根据环境/配置文件有条件地进行处理
可以在创建Jackson2JsonEncoder
时通过编解码器指定此自定义日志记录编码器:
WebClient
更新2020/7/3:
这是一个应用相同原理但仅适用于解码器的匆忙示例:
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);
}
}
}
上的codecs
构建器方法将其与编码器一起配置。
当然,以上假设只适用于将您的数据反序列化为Mono的情况。但是,如果需要,请覆盖其他方法。另外,我只是在这里输出结果JSON,但是您可以传入WebClient
或其他东西,以使解码器将字符串发送到,例如,或者只是从那里登录;由你决定。
警告一句,以目前的形式,这将使您的内存使用量增加一倍,因为它会缓冲整个响应。如果您可以将该字节数据发送到另一个进程/线程以立即写入日志文件或某些输出流(甚至Flux),则可以避免将整个有效负载缓冲在内存中。
答案 1 :(得分:0)
尝试设置以下属性:
logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions=TRACE
logging.level.reactor.netty.http.client.HttpClient: DEBUG
spring.http.log-request-details=true