过滤器和拦截器的区别是什么?

#Java#面试八股

过滤器和拦截器的区别是什么?

结论先行:Filter 是 Servlet 规范定义的组件,由容器(Tomcat)在请求进入 DispatcherServlet 之前调用,能改请求/响应对象;HandlerInterceptor 是 Spring MVC 的组件,在 DispatcherServlet 内部、Handler 执行前后调用,能拿到 HandlerMethod(哪个 Controller 的哪个方法)。一句话:Filter 管「进容器」,Interceptor 管「进 Controller」。

1. 在请求链路中的位置

客户端
  │
  ▼
FilterChain(容器级,可多个)
  │  ① Filter.doFilter
  ▼
DispatcherServlet
  │
  ├─ HandlerMapping 找到 Handler
  ├─ HandlerInterceptor.preHandle      ← 返回 false 则中断
  ├─ HandlerAdapter 调用 Controller
  ├─ HandlerInterceptor.postHandle
  ├─ 视图渲染 / @ResponseBody 序列化
  └─ HandlerInterceptor.afterCompletion
  │
  ▼
Filter 的后置逻辑(chain.doFilter 之后的代码)

顺序很关键:Filter 在 DispatcherServlet 外,Interceptor 在里,所以 Filter 的 doFilter 后置代码最后执行。

2. 对比表

维度FilterHandlerInterceptor
规范来源Servlet(javax/jakarta.servlet)Spring MVC
作用范围所有进入容器的请求(含静态资源)只有被 DispatcherServlet 处理的请求
触发时机请求进入容器后、Servlet 之前Handler 查找之后、执行前后
能否拿到 Handler否,只有 ServletRequest能,preHandle 参数含 HandlerMethod
典型用途编码、CORS、XSS 过滤、请求体包装、全链路 TraceId登录校验、权限、日志、参数预处理
中断方式不调 chain.doFilterpreHandle 返回 false

3. 代码:Filter

@Component
@Order(1)                                  // 数值越小越先执行
public class TraceIdFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String traceId = req.getHeader("X-Trace-Id");
        if (traceId == null) {
            traceId = UUID.randomUUID().toString().replace("-", "");
        }
        MDC.put("traceId", traceId);        // 日志链路

        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("X-Trace-Id", traceId);
        try {
            chain.doFilter(request, response);   // 放行
        } finally {
            MDC.clear();                          // 防止线程复用导致串号
        }
    }
}

注册方式:@Component 即可(Spring Boot 自动注册),或用 FilterRegistrationBean 精确控制顺序与 URL 匹配。

4. 代码:Interceptor

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                             Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod method)) {
            return true;                     // 静态资源等直接放行
        }
        if (method.hasMethodAnnotation(PublicApi.class)) {
            return true;                     // 白名单注解
        }
        String token = request.getHeader("Authorization");
        if (token == null || !JwtUtil.verify(token)) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;                    // 中断,不再进入 Controller
        }
        return true;
    }
}
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/auth/**", "/error");
    }
}

5. 怎么选

需求选择原因
统一编码、CORS、请求体缓存Filter需要在 Servlet 解析参数前处理
全链路 TraceId、访问日志Filter覆盖所有请求,包括 404
登录/权限校验Interceptor能读注解、能拿到 HandlerMethod
需要环绕 Controller 的 AOP 语义拦截器或 AOPFilter 拿不到方法信息

6. 常见追问

追问一:Filter 里能注入 Spring Bean 吗? 能,但必须由 Spring 管理(@Component 或 FilterRegistrationBean)。若在 web.xml 里配置,容器创建的是自己的实例,@Autowired 不生效,需要用 WebApplicationContextUtils 手动取。

追问二:多个 Filter 的顺序怎么定? @Order 或 FilterRegistrationBean.setOrder(),数值小的先执行。Spring Security 的过滤器链 order 是 -100,业务过滤器要排在它之后(数值更大),否则拿不到 SecurityContext。

追问三:preHandle 返回 false 后,afterCompletion 还会执行吗? 不会。只有 preHandle 返回 true 的拦截器才会在请求完成后调用 afterCompletion。所以资源释放要放在 afterCompletion 里,并注意它与 preHandle 的配对。

追问四:Filter 和 AOP 有什么区别? AOP 基于方法调用,能精确到方法、参数、返回值,适合事务、日志;Filter 基于 HTTP 请求,粒度是「请求」,拿不到方法签名。三者常组合:Filter 做编码与 TraceId,Interceptor 做鉴权,AOP 做业务日志。

追问五:OncePerRequestFilter 是什么? Spring 提供的 Filter 基类,保证一次请求只执行一次(内部用 request attribute 标记)。异步请求、forward 场景下,普通 Filter 可能被多次调用,用它更安全。

小结

区别可以压缩成一句话:Filter 是容器的门卫,Interceptor 是 MVC 的前台。门卫能查所有进出的人但不知道你要找谁;前台知道你要找哪个部门(HandlerMethod),但只管进了大楼的人。选型就看你要不要「方法级信息」和「是否覆盖静态资源」。

笔记加载中…