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

如何避免WebFlux异常追踪中记录含敏感信息的Checkpoint

解决WebFlux异常追踪中敏感URI的日志泄露问题

问题背景

使用DefaultWebClient调用下游API时,URI路径包含敏感数据。异常场景下WebFlux会将下游URI作为追踪信息的一部分,以WARN级别日志输出。现有约束:

  • 禁止关闭WARN级别日志
  • 无法重写DefaultWebClient.java、Mono.java或WebClientUtils.java
  • 当前使用WebFlux 3.3.7版本,已尝试checkpoint()、checkpoint("test checkpoint")、hide()、log("abc", Level.SEVERE)等方法,仍能看到包含敏感URI的checkpoint日志。

调用代码示例:

public Mono<DataResponse> callDownstream(String sensitiveId) {
    return webClient.get()
        .uri("URI-PATH", sensitiveId)
        .retrieve()
        .onStatus(HttpStatusCode::isError, resp -> resp.bodyToMono(ErrorDto.class).map(this::httpError))
        .bodyToMono(DataResponse.class)
        .doFinally(signalType -> log.info(String.format("message=\"Finished calling downstream\"")));
}


private Throwable httpError(ErrorDto errorDto) {
  log.error("message=\"Error in calling downstream\"");
  return new CustomException("Error in calling downstream");
}

异常日志片段示例:

Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
*__checkpoint ⇢ 500 INTERNAL_SERVER_ERROR from GET https://example.com:8081/my-service/manage/*SENSITIVE-DATA [DefaultWebClient]
...(后续堆栈信息略)

可行解决方案

1. 自定义ExchangeFilterFunction脱敏URI

通过添加ExchangeFilterFunction,在请求链路中替换日志展示用的URI(实际请求仍使用原URI),让DefaultWebClient生成的checkpoint使用脱敏后的URI:

// 构建脱敏后的WebClient实例
WebClient maskedWebClient = webClient.mutate()
    .filter((request, next) -> {
        // 根据实际URI结构编写脱敏逻辑
        String originalUri = request.url().toString();
        String maskedUri = originalUri.replaceAll("/manage/([^/]+)", "/manage/***");
        
        // 创建包装后的请求,使用脱敏URI
        ClientRequest maskedRequest = ClientRequest.from(request)
                .url(URI.create(maskedUri))
                .build();
        
        return next.exchange(maskedRequest);
    })
    .build();

核心逻辑:DefaultWebClient的checkpoint信息基于ClientRequest的url()生成,替换后checkpoint会输出脱敏后的内容。

2. 异常包装+hide()清除追踪信息

通过onErrorMap包装自定义异常,避免触发FluxOnAssembly的敏感URI追踪,结合hide()隐藏操作符链路:

public Mono<DataResponse> callDownstream(String sensitiveId) {
    return webClient.get()
        .uri("URI-PATH", sensitiveId)
        .retrieve()
        .onStatus(HttpStatusCode::isError, resp -> resp.bodyToMono(ErrorDto.class).map(this::httpError))
        .bodyToMono(DataResponse.class)
        .doFinally(signalType -> log.info("message=\"Finished calling downstream\""))
        .onErrorMap(ex -> {
            if (ex instanceof CustomException) {
                // 包装异常,跳过栈填充避免Assembly追踪
                return new CustomException(ex.getMessage(), ex.getCause()) {
                    @Override
                    public Throwable fillInStackTrace() {
                        return this;
                    }
                };
            }
            return ex;
        })
        .hide();
}

注意:此方式会减少部分调试链路信息,但能有效避免敏感URI泄露。

3. 日志框架层面脱敏输出

针对Logback/Log4j2等日志框架,自定义转换器在日志输出环节直接清洗敏感内容:

以Logback为例,自定义脱敏转换器:

public class MaskingConverter extends ClassicConverter {
    @Override
    public String convert(ILoggingEvent event) {
        String message = event.getFormattedMessage();
        // 根据实际URI规则替换敏感部分
        return message.replaceAll("GET https://example.com:8081/my-service/manage/([^/]+)", "GET https://example.com:8081/my-service/manage/***");
    }
}

在logback.xml中配置使用该转换器:

<conversionRule conversionWord="maskedMsg" converterClass="com.yourpackage.MaskingConverter"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %maskedMsg%n</pattern>
    </encoder>
</appender>

核心逻辑:在日志最终输出环节拦截并清洗敏感内容,从根源避免敏感数据落地。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 08:48:12