Spring WebFlux REST API(注解控制器)请求总处理时间统计咨询
嘿,这个需求很常见,用Spring WebFlux的WebFilter完全能搞定,我给你一步步拆解实现方法:
核心思路
WebFlux是响应式编程模型,所以我们需要在请求进入时记录起始时间,然后监听响应的完成信号(不管成功还是失败),再计算时间差。ServerWebExchange自带的属性Map正好可以用来存储每个请求的起始时间,它是请求级别的,完全不用担心线程安全问题。
具体实现代码
先写一个自定义的WebFilter,Spring会自动把它加入到过滤器链中:
import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import java.time.Instant; import java.time.Duration; @Component public class RequestTimingFilter implements WebFilter { // 定义属性键的常量,避免硬编码 private static final String REQUEST_START_TIME = "REQUEST_START_TIME"; @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { // 1. 记录请求起始时间,存入ServerWebExchange的属性中 Instant startTime = Instant.now(); exchange.getAttributes().put(REQUEST_START_TIME, startTime); // 2. 继续执行后续的过滤器和控制器逻辑 return chain.filter(exchange) // 3. 响应成功完成时计算时长 .doOnSuccess(aVoid -> calculateAndLogDuration(exchange, startTime)) // 4. 请求出错时也要统计时长 .doOnError(throwable -> { calculateAndLogDuration(exchange, startTime); System.err.printf("请求 %s 处理失败,错误信息: %s%n", exchange.getRequest().getPath(), throwable.getMessage()); }); } private void calculateAndLogDuration(ServerWebExchange exchange, Instant startTime) { Instant endTime = Instant.now(); Duration duration = Duration.between(startTime, endTime); long durationMillis = duration.toMillis(); // 这里可以替换成日志框架(如SLF4J),或者上报到监控系统 System.out.printf("请求路径: %s,HTTP方法: %s,处理总时长: %d ms%n", exchange.getRequest().getPath(), exchange.getRequest().getMethod(), durationMillis); // 可选:把时长放到响应头返回给客户端 exchange.getResponse().getHeaders().add("X-Request-Duration", String.valueOf(durationMillis)); } }
关键细节解释
- 存储起始时间:用
exchange.getAttributes()获取请求级别的Map,把起始时间存进去,每个请求的属性都是独立的,不会互相干扰。 - 响应式监听:因为WebFlux是异步的,必须通过
doOnSuccess和doOnError来监听响应的完成信号,不能像Servlet那样在过滤器末尾直接计算(那样会拿到错误的时间,因为请求还没处理完)。 - 异常场景覆盖:不管请求成功还是失败,都要统计时长,所以两个回调都要处理。
- 精确时间计算:用
Instant和Duration比System.currentTimeMillis()更精确,适合需要细粒度监控的场景。
额外扩展
如果需要更复杂的监控(比如按接口统计平均时长、QPS等),可以把时长数据存入Micrometer这类监控工具,结合Prometheus+Grafana做可视化,但基础的统计逻辑就是上面这样。
内容的提问来源于stack exchange,提问作者Leo Prince
相关产品推荐
相关产品推荐

