如何记录 spring-webflux WebClient 请求 + 响应详细信息(正文、标头、elasped_time)?
Posted
技术标签:
【中文标题】如何记录 spring-webflux WebClient 请求 + 响应详细信息(正文、标头、elasped_time)?【英文标题】:How to log spring-webflux WebClient request + response details (bodies, headers, elasped_time)? 【发布时间】:2019-10-02 08:02:47 【问题描述】:基本上,我想在一个日志中记录请求/响应信息,其中包含带有 Spring WebClient
的正文/标头。
使用 Spring RestTemplate
,我们可以使用 ClientHttpRequestInterceptor
。我为 Spring WebClient
找到了 ExchangeFilterFunction
,但还没有设法以干净的方式做类似的事情。我们可以使用这个过滤器并记录请求,然后记录响应,但我需要在同一个日志跟踪中。
此外,我还没有设法使用ExchangeFilterFunction.ofResponseProcessor
方法获取响应正文。
我希望这样的日志(当前实现使用 ClientHttpRequestInterceptor)包含我需要的所有信息:
"@timestamp": "2019-05-14T07:11:29.089+00:00",
"@version": "1",
"message": "GET https://awebservice.com/api",
"logger_name": "com.sample.config.resttemplate.LoggingRequestInterceptor",
"thread_name": "http-nio-8080-exec-5",
"level": "TRACE",
"level_value": 5000,
"traceId": "e65634ee6a7c92a7",
"spanId": "7a4d2282dbaf7cd5",
"spanExportable": "false",
"X-Span-Export": "false",
"X-B3-SpanId": "7a4d2282dbaf7cd5",
"X-B3-ParentSpanId": "e65634ee6a7c92a7",
"X-B3-TraceId": "e65634ee6a7c92a7",
"parentId": "e65634ee6a7c92a7",
"method": "GET",
"uri": "https://awebservice.com/api",
"body": "[Empty]",
"elapsed_time": 959,
"status_code": 200,
"status_text": "OK",
"content_type": "text/html",
"response_body": ""message": "Hello World!""
有没有人设法用 Spring WebClient 做这样的事情?或者如何继续使用 Spring WebClient 跟踪请求/响应问题?
【问题讨论】:
【参考方案1】:你可以使用 filter(),像这样:
this.webClient = WebClient.builder().baseUrl("your_url")
.filter(logRequest())
.filter(logResponse())
.build();
private ExchangeFilterFunction logRequest()
return (clientRequest, next) ->
log.info("Request: ", clientRequest.method(), clientRequest.url());
clientRequest.headers()
.forEach((name, values) -> values.forEach(value -> log.info("=", name, value)));
return next.exchange(clientRequest);
;
private ExchangeFilterFunction logResponse()
return ExchangeFilterFunction.ofResponseProcessor(clientResponse ->
log.info("Response: ", clientResponse.headers().asHttpHeaders().get("property-header"));
return Mono.just(clientResponse);
);
【讨论】:
我知道这一点,但这不会在同一日志中生成包含请求信息和响应信息的日志。我正在寻找一种同时记录两者的方法。此答案生成一个请求日志和一个响应日志。 您无法使用 Exchange 过滤器记录请求正文 @StefanHaberl 是的,你可以,在函数.ofRequestProcessor()
中使用ExchangeFilterFunction
【参考方案2】:
我认为您不能两次调用.bodyToMono
(一次在过滤器中,然后在您使用客户端的地方再次调用),因此您可能无法在过滤器中记录它。至于其他细节……
WebClient 配置:
@Configuration
class MyClientConfig
@Bean
fun myWebClient(): WebClient
return WebClient
.builder()
.baseUrl(myUrl)
.filter(MyFilter())
.build()
过滤器:
class MyFilter : ExchangeFilterFunction
override fun filter(request: ClientRequest, next: ExchangeFunction): Mono<ClientResponse>
return next.exchange(request).flatMap response ->
// log whenever you want here...
println("request: $request.url(), response: $response.statusCode()")
Mono.just(response)
【讨论】:
以上是关于如何记录 spring-webflux WebClient 请求 + 响应详细信息(正文、标头、elasped_time)?的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有 spring-boot 的情况下在 spring-webflux 中加载配置?
如何在 spring-webflux RouterFunction 端点中使用 OpenApi 注释?