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

如何记录Spring 5 WebClient调用

司空海荣
2023-03-14

我正在尝试使用Spring 5 WebClient记录请求。你知道我怎样才能做到吗?

(我使用的是Spring5和Spring靴2)

代码目前如下所示:

try {
    return webClient.get().uri(url, urlParams).exchange().flatMap(response -> response.bodyToMono(Test.class))
            .map(test -> xxx.set(test));
} catch (RestClientException e) {
    log.error("Cannot get counter from opus", e);
    throw e;
}

共有3个答案

南门鸿振
2023-03-14

您不一定需要运行自己的记录器,reactor。ipc。内蒂。频道ChannelOperationsHandler为您执行此操作。只需为该类配置日志记录系统,以便在调试级别进行日志记录:

2017-11-23 12:52:04.562 DEBUG 41449 --- [ctor-http-nio-5] r.i.n.channel.ChannelOperationsHandler   : [id: 0x9183d6da, L:/127.0.0.1:57681 - R:localhost/127.0.0.1:8000] Writing object DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0))
GET /api/v1/watch/namespaces/default/events HTTP/1.1
user-agent: ReactorNetty/0.7.1.RELEASE
host: localhost:8000
accept-encoding: gzip
Accept: application/json
content-length: 0

减少bug的一种方法是尽可能不编写代码。

十一月2018:

使用<代码>spring webflux:5.1.2。发布后,上述操作将不再有效。请使用以下选项:

logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions=DEBUG
...
2018-11-06 20:58:58.181 DEBUG 20300 --- [           main] o.s.w.r.f.client.ExchangeFunctions       : [2026fbff] HTTP GET http://localhost:8080/stocks/search?symbol=AAPL
2018-11-06 20:58:58.451 DEBUG 20300 --- [ctor-http-nio-4] o.s.w.r.f.client.ExchangeFunctions       : [2026fbff] Response 400 BAD_REQUEST

要记录标题或表单正文,请将上述设置为跟踪级别;然而,这还不够:

ExchangeStrategies exchangeStrategies = ExchangeStrategies.withDefaults();
exchangeStrategies
    .messageWriters().stream()
    .filter(LoggingCodecSupport.class::isInstance)
    .forEach(writer -> ((LoggingCodecSupport)writer).setEnableLoggingRequestDetails(true));

client = WebClient.builder()
    .exchangeStrategies(exchangeStrategies)

2019年3月:

在回答评论中关于如何记录请求和响应正文的问题时,我不知道Spring是否有这样的记录器,但WebClient是构建在Netty上的,因此启用包reactor的调试日志记录。ipc。netty应该和这个答案一起工作。

华锦程
2023-03-14

您可以通过要求它进行窃听来记录请求/响应,如果您像这样创建Spring WebClient,那么它会启用窃听选项。

        WebClient webClient = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create().wiretap(true)
            ))
            .build()

然后进行日志记录设置:

logging.level.reactor.netty.http.client.HttpClient: DEBUG

这将记录请求/响应的所有内容(包括主体),但格式并不特定于HTTP,因此不太易读。

祁飞扬
2023-03-14

您可以使用ExchangeFilterFunction轻松完成此操作

使用网络客户端创建网络客户端时,只需添加自定义日志请求过滤器。生成器。

下面是此类过滤器的示例,以及如何将其添加到Web客户端。

@Slf4j
@Component
public class MyClient {

    private final WebClient webClient;

    // Create WebClient instance using builder.
    // If you use spring-boot 2.0, the builder will be autoconfigured for you
    // with the "prototype" scope, meaning each injection point will receive
    // a newly cloned instance of the builder.
    public MyClient(WebClient.Builder webClientBuilder) {
        webClient = webClientBuilder // you can also just use WebClient.builder()
                .baseUrl("https://httpbin.org")
                .filter(logRequest()) // here is the magic
                .build();
    }

    // Just example of sending request. This method is NOT part of the answer
    public void send(String path) {
        ClientResponse clientResponse = webClient
                .get().uri(uriBuilder -> uriBuilder.path(path)
                        .queryParam("param", "value")
                        .build())
                .exchange()
                .block();
        log.info("Response: {}", clientResponse.toEntity(String.class).block());
    }

    // This method returns filter function which will log request data
    private static ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value)));
            return Mono.just(clientRequest);
        });
    }

}

然后只需调用myClient。发送(“获取”) 和日志消息。

输出示例:

Request: GET https://httpbin.org/get?param=value
header1=value1
header2=value2

编辑

一些人在评论中指出,block()是不好的做法。我想澄清:block()这里的调用只是为了演示。请求日志过滤器无论如何都会工作。您无需向代码中添加block(),即可使ExchangeFilterFunction正常工作。您可以使用WebClient以常规方式执行http调用,链接方法并返回堆栈上的Mono,直到有人订阅为止。答案中唯一相关的部分是过滤。您可以完全忽略send()方法-它不是解决方案的一部分-它只是演示了过滤器的工作原理。

一些人还问如何记录回应。要记录响应,可以编写另一个ExchangeFilterFunction,并将其添加到WebClient。您可以使用ExchangeFilterFunction。响应处理器的帮助程序的方法与ExchangeFilterFunction的方法相同。使用了请求处理器(ofRequestProcessor)。您可以使用ClientResponse的方法获取标题/cookie等。

    // This method returns filter function which will log response data
    private static ExchangeFilterFunction logResponse() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            log.info("Response status: {}", clientResponse.statusCode());
            clientResponse.headers().asHttpHeaders().forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value)));
            return Mono.just(clientResponse);
        });
    }

不要忘记将其添加到您的网络客户端:

.filter(logResponse())

但要小心,不要试图读取过滤器中的响应正文。由于它的流性质,在没有某种缓冲包装器的情况下,身体只能消费一次。因此,如果您将在过滤器中读取它,那么您将无法在订阅服务器中读取它。

如果确实需要记录正文,可以使用底层(Netty)来完成此操作。请参阅Matthew Buckett的答案以了解想法。

 类似资料:
  • 我正在使用Fiegn创建一个REST客户端。我已经让我的调用正常工作了,但我想记录回退方法调用的异常which tigger 代码如下: 发生异常时可以调用回退方法,但记录注意事项。 如何记录触发调用的回退方法的异常? 如connectionTimeoutException。

  • 我有一个简单的Java程序,它使用SpringWebClient发送多个请求。每个都返回一个mono,我使用的是response。subscribe()以检查结果。 但是,我的主执行线程在处理所有请求之前完成,除非我添加一个长线程。睡眠()。 对于CompletableFutures,您可以使用:CompletableFuture。allOf(期货)。join(); 有没有办法等待所有单声道的完成

  • 我将事件发送到AWS Kinesis,这些事件由AWS lambda函数处理。但是,如果lambda抛出一些错误,则不会丢弃记录,并且会一次又一次地进行处理,从而阻止处理新记录。 我宁愿跳过错误的记录,消化新的记录。我不知道该怎么做。 lambda函数捕获任何异常,因此不应给出任何执行错误。 下面是python中的片段。 我知道lambda应该在“保留”期间重试(默认为24小时),但我希望放弃并最

  • 我正在调用Apache Camel XML DSL中的Javascript文件,该文件在Apache ServiceMix中运行,如下所示: 我想在myJavascript中记录一条消息。这样消息就会显示在主Camel上下文日志中。 这里的Camel文档表示传递了CamelContext Java对象。我希望它能为记录器提供一个getter,这样我就可以在脚本中做这样的事情: 然而,这里并没有提到

  • Java16引入了记录,这有助于在编写携带不可变数据的类时减少样板代码。当我尝试将记录用作bean时,我得到以下错误消息: 如何将记录用作?

  • 但是Crawler4J中有一个记录器。 如何禁用记录器内部爬行4J库?