首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何记录Spring 5 WebClient调用

如何记录Spring 5 WebClient调用
EN

Stack Overflow用户
提问于 2017-09-11 11:46:07
回答 18查看 108.7K关注 0票数 76

我试图使用Spring5 WebClient记录一个请求。你知道我怎么能做到这一点吗?

(我使用Spring 5和Spring 2)

目前的代码如下:

代码语言:javascript
运行
复制
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;
}
EN

回答 18

Stack Overflow用户

回答已采纳

发布于 2017-10-21 20:32:42

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

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

下面是这种过滤器的示例,以及如何将其添加到WebClient中。

代码语言:javascript
运行
复制
@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");,日志消息就应该在那里。

输出示例:

代码语言:javascript
运行
复制
Request: GET https://httpbin.org/get?param=value
header1=value1
header2=value2

编辑

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

一些人还询问如何记录回复。要记录响应,可以编写另一个ExchangeFilterFunction并将其添加到WebClient中。您可以使用ExchangeFilterFunction.ofResponseProcessor助手来实现这个目的,就像使用ExchangeFilterFunction.ofRequestProcessor一样。您可以使用ClientResponse的方法获取标头/cookie等。

代码语言:javascript
运行
复制
    // 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

代码语言:javascript
运行
复制
.filter(logResponse())

但是要小心,不要试图在这里读取过滤器中的响应体。由于它的流性质,在没有缓冲包装的情况下,人体只能消耗一次。因此,如果要在筛选器中读取它,则无法在订阅服务器中读取它。

如果您确实需要对主体进行日志记录,则可以使用底层(Netty)来完成此操作。请看马修·布克特的回答以获得这个想法。

票数 58
EN

Stack Overflow用户

发布于 2019-04-22 07:22:45

您可以使用netty记录请求/响应,方法是要求它执行窃听操作,如果您像这样创建Spring,那么它就启用了窃听选项。

代码语言:javascript
运行
复制
        WebClient webClient = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create().wiretap(true)
            ))
            .build()

然后让您的日志设置:

代码语言:javascript
运行
复制
logging.level.reactor.netty.http.client.HttpClient: DEBUG

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

票数 50
EN

Stack Overflow用户

发布于 2021-01-29 18:18:29

在SpringBoot2.4.0中,HttpClient的wiretap()方法具有可以传递的附加参数,以普通人类可读的格式显示完整的请求/响应头和正文。使用格式(AdvancedByteBufFormat.TEXTUAL)。

代码语言:javascript
运行
复制
HttpClient httpClient = HttpClient.create()
      .wiretap(this.getClass().getCanonicalName(), LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL);
ClientHttpConnector conn = new ReactorClientHttpConnector(httpClient);   

WebClient client =  WebClient.builder()
            .clientConnector(conn)
            .build();

结果:

代码语言:javascript
运行
复制
POST /score HTTP/1.1
Host: localhost:8080
User-Agent: insomnia/2020.5.2
Content-Type: application/json
access_: 
Authorization: Bearer eyJ0e....
Accept: application/json
content-length: 4506

WRITE: 4506B {"body":{"invocations":[{"id":....


READ: 2048B HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 2271
Server: Werkzeug/1.0.1 Python/3.7.7
Date: Fri, 29 Jan 2021 18:49:53 GMT

{"body":{"results":[.....
票数 41
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46154994

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档