如何记录 Spring 5 WebClient 调用 [英] how to log Spring 5 WebClient call

查看:41
本文介绍了如何记录 Spring 5 WebClient 调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Spring 5 WebClient 记录请求.你知道我怎么能做到这一点吗?

I'm trying to log a request using Spring 5 WebClient. Do you have any idea how could I achieve that?

(我使用的是 Spring 5 和 Spring Boot 2)

(I'm using Spring 5 and Spring boot 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;
}

推荐答案

您可以使用 ExchangeFilterFunction

只需在使用 WebClient.Builder 创建 WebClient 时添加自定义 logRequest 过滤器即可.

Just add the custom logRequest filter when you create your WebClient using WebClient.Builder.

这是此类过滤器的示例以及如何将其添加到 WebClient.

Here is the example of such filter and how to add it to the WebClient.

@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.send("get"); 并且日志消息应该在那里.

Then just call myClient.send("get"); and log messages should be there.

输出示例:

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

编辑

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

Some people pointed out in comments that block() is bad practice etc. I want to clarify: block() call here is just for demo purposes. The request logging filter will work anyway. You will not need to add block() to your code to make ExchangeFilterFunction work. You can use WebClient to perform a http-call in a usual way, chaining methods and returning Mono up the stack until someone will subscribe to it. The only relevant part of the answer is logRequest() filter. You can ignore send() method altogether - it is not part of the solution - it just demonstrates that filter works.

有些人还询问了如何记录响应.要记录响应,您可以编写另一个 ExchangeFilterFunction 并将其添加到 WebClient.您可以使用 ExchangeFilterFunction.ofResponseProcessor 用于此目的的帮助程序与使用 ExchangeFilterFunction.ofRequestProcessor 的方式相同.您可以使用 ClientResponse 获取标题/cookies 等

Some people also asked how to log the response. To log the response you can write another ExchangeFilterFunction and add it to WebClient. You can use ExchangeFilterFunction.ofResponseProcessor helper for this purpose just the same way as ExchangeFilterFunction.ofRequestProcessor is used. You can use methods of ClientResponse to get headers/cookies etc.

    // 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);
        });
    }

不要忘记将它添加到您的WebClient:

Don't forget to add it to your WebClient:

.filter(logResponse())

但要小心,不要试图在过滤器中读取响应正文.由于它的流性质,body 只能被消耗一次,而无需某种缓冲包装器.所以,如果你在过滤器中阅读,你将无法在订阅者中阅读.

But be careful and do not try to read the response body here in the filter. Because of the stream nature of it, the body can be consumed only once without some kind of buffering wrapper. So, if you will read it in the filter, you will not be able to read it in the subscriber.

如果真的需要log body,可以让底层(Netty)来做这个.请参阅马修巴克特的回答以了解这个想法.

If you really need to log the body, you can make the underlying layer (Netty) to do this. See Matthew Buckett's answer to get the idea.

这篇关于如何记录 Spring 5 WebClient 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆