You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何记录封装WebClient的第三方API的请求与响应?

拦截WebClient封装的HTTP请求并记录日志

当然可以,Spring WebClient提供了原生的拦截机制ExchangeFilterFunction,不管是自研的WebClient实例,还是第三方API封装的WebClient,只要能接触到WebClient的构建器或实例,就能通过添加过滤器拦截并记录请求/响应的完整通信细节。

核心实现:自定义日志拦截过滤器

通过ExchangeFilterFunction可以分别拦截请求发送前和响应返回后的处理逻辑,示例代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import reactor.core.publisher.Mono;

public class WebClientLoggingFilter {
    private static final Logger logger = LoggerFactory.getLogger(WebClientLoggingFilter.class);

    public static ExchangeFilterFunction logRequestResponse() {
        // 拦截并记录请求
        ExchangeFilterFunction requestFilter = ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            logger.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            // 打印请求头(生产环境可调整为DEBUG级别避免冗余)
            clientRequest.headers().forEach((headerName, values) -> 
                values.forEach(value -> logger.debug("Request Header: {} = {}", headerName, value)));
            return Mono.just(clientRequest);
        });

        // 拦截并记录响应
        ExchangeFilterFunction responseFilter = ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            logger.info("Response: {} {}", clientResponse.statusCode(), clientResponse.request().url());
            // 打印响应头
            clientResponse.headers().asHttpHeaders().forEach((headerName, values) -> 
                values.forEach(value -> logger.debug("Response Header: {} = {}", headerName, value)));
            
            // 必须缓存响应体,避免下游无法读取原始响应
            return clientResponse.cache();
        });

        return requestFilter.andThen(responseFilter);
    }
}

不同场景下的添加方式

  1. 自研WebClient实例
    创建WebClient时直接添加过滤器:
WebClient webClient = WebClient.builder()
        .baseUrl("https://api.example.com")
        .filter(WebClientLoggingFilter.logRequestResponse())
        .build();
  1. 第三方封装的WebClient Bean
    如果第三方将WebClient作为Spring Bean暴露,可在配置类中修改Bean定义:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient thirdPartyWebClient(WebClient.Builder webClientBuilder) {
        return webClientBuilder
                // 假设第三方的WebClient原本有其他配置,这里追加日志过滤器
                .filter(WebClientLoggingFilter.logRequestResponse())
                .build();
    }
}
  1. 全局拦截所有WebClient实例
    如果需要拦截所有通过WebClient.Builder创建的WebClient(包括第三方内部构建的),使用WebClientCustomizer实现全局配置:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClientCustomizer;

@Configuration
public class GlobalWebClientLoggingConfig {
    @Bean
    public WebClientCustomizer webClientLoggingCustomizer() {
        return builder -> builder.filter(WebClientLoggingFilter.logRequestResponse());
    }
}

注意事项

  • 记录响应体时,必须调用clientResponse.cache(),否则响应体被日志逻辑消费后,下游业务代码将无法读取响应内容。如果需要打印响应体内容,可通过clientResponse.bodyToMono(String.class)读取后再重新封装响应。
  • 生产环境需注意日志级别,避免敏感信息(如Authorization头、请求体中的密码)被泄露,建议对敏感字段做脱敏处理。
  • 如果第三方封装的WebClient完全隐藏了实例和构建器,无法通过上述方式添加过滤器,可考虑用AOP拦截其请求方法,但这种方式复杂度较高,优先推荐使用ExchangeFilterFunction。

内容的提问来源于stack exchange,提问作者StSch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 12:30:09