首页 > 解决方案 > WebClient 请求的简单日志转储?

问题描述

我正在尝试使用 SpringWebClient进行一些基本的 REST API 调用。我收到请求格式错误的错误,但我无法确切说明原因。有什么方法可以轻松记录请求的内容(真的,只是请求正文)?我在网上找到的一切都超级复杂。这是我所拥有的:

LinkedMultiValueMap params = new LinkedMultiValueMap();
params.add("app_id", getOneSignalAppId());
params.add("included_segments", inSegment);
params.add("content_available", true);
params.add("contents", new LinkedMultiValueMap() {{
                            add("en", inTitle);
                        }});

BodyInserters.MultipartInserter inserter = BodyInserters.fromMultipartData(params);

WebClient client = WebClient.builder()
                                .baseUrl("https://onesignal.com")
                                .defaultHeader(HttpHeaders.AUTHORIZATION, "Basic " + getOneSignalKey())
                                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                                .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                            .build();
Mono<NotificationResponse> result = client
                                .post()
                                .uri("/api/v1/notifications")
                                .body(inserter)
                                .retrieve()
                                .bodyToMono(NotificationResponse.class);

我只想要一个将插入到请求正文中的 JSON 字符串。

标签: springwebclient

解决方案


您可以围绕 JSON 编码器创建自己的包装器/代理类(假设您使用的是 JSON)并在将序列化主体发送到 intertubes 之前拦截它。

如果您的请求要发送 JSON。具体来说,您将扩展(默认编码器)的encodeValue方法(或encodeValues在流数据的情况下)。Jackson2JsonEncoder然后,您可以根据需要对这些数据执行任何操作,例如日志记录等。您甚至可以根据环境/配置文件有条件地执行此操作。

可以在创建 时指定此自定义日志编码器,方法WebClient是将其作为编解码器提供:

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

我为此写了一篇博文。您也许可以找到 Multipart 数据的编码器并应用类似的原则

为了完整起见,编码器可能如下所示:

public class CustomBodyLoggingEncoder extends Jackson2JsonEncoder {
    @Override
    public DataBuffer encodeValue(final Object value, final DataBufferFactory bufferFactory,
                                  final ResolvableType valueType, @Nullable final MimeType mimeType, @Nullable final Map<String, Object> hints) {

        // Encode/Serialize data to JSON
        final DataBuffer data = super.encodeValue(value, bufferFactory, valueType, mimeType, hints);

        // This is your code:
        SomethingAmazing.doItWithThisData(extractBytes(data));

        // Return the data as normal
        return data;
    }

    private byte[] extractBytes(final DataBuffer data) {
        final byte[] bytes = new byte[data.readableByteCount()];
        data.read(bytes);
        // We've copied the data above to our array, but must reset the buffer for actual usage
        data.readPosition(0);
        return bytes;
    }
}

希望能有所帮助!


推荐阅读