OncePerRequestFilter 的作用与使用场景

作用

OncePerRequestFilter 是 Spring 提供的一个抽象基类,它继承自 GenericFilterBean 并实现了 Filter 接口。它的主要目的是确保在一次请求中过滤器逻辑只执行一次

当一个 HTTP 请求进入应用时,可能会被多个 Filter 处理。而某些情况下(例如异步请求或转发请求),同一个 Filter 可能会被调用多次。为了避免重复处理带来的副作用,Spring 提供了 OncePerRequestFilter 来保证每个请求只会触发该过滤器一次。

使用场景
  1. 跨域配置

    • 避免在请求链路中有多个相同 CORS 设置操作。
  2. 权限验证 / 认证

    • 在请求到达业务逻辑前检查用户身份认证状态。
    • 确保不会因为多次拦截导致重复校验 token 或 session。
  3. 日志记录

    • 统计请求耗时、记录访问日志等。
    • 保证每条请求只统计一次,避免数据混乱。
  4. 请求包装

    • 对原始 HttpServletRequest 进行增强或替换。
    • 比如解密 body 内容、统一参数预处理等。

常见使用案例

@Component
@WebFilter(filterName = "loggingFilter", urlPatterns = "/*")
public class LoggingFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        
        long startTime = System.currentTimeMillis();
        String uri = request.getRequestURI();
        
        logger.info("Request started: {} {}", request.getMethod(), uri);
        
        try {
            // 继续执行后续过滤器和目标资源
            filterChain.doFilter(request, response);
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            logger.info("Request finished: {} {} took {} ms", request.getMethod(), uri, duration);
        }
    }
}

在这个例子中:

  • 日志只会在请求开始和结束各打印一次。
  • 即使有其他 Filter 调用了多次当前 LoggingFilter 实例的方法,由于其继承了 OncePerRequestFilter,实际的方法也只会被执行一次。
  • 从而有效防止日志重复输出的问题。

总结来说,如果你希望某个 Filter 的核心逻辑对每一个 HTTP 请求仅运行一次,则推荐继承 OncePerRequestFilter 并重写 doFilterInternal() 方法来实现具体功能。

以上内容由AI大模型生成,注意识别!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐