文档站点
Skip to content

中间件(Interceptor / Filter) ​

Laravel 的中间件有「全局中间件」和「路由中间件」两层,还有 before/after 时机。Spring 对应有两套机制:Filter(Servlet 层) 和 HandlerInterceptor(Spring MVC 层)。先记住区别,就不会再混淆。

Filter 与 Interceptor 的区别(最重要的认知) ​

维度FilterHandlerInterceptor
所属层次Servlet 容器层Spring MVC 层
能否拿到 Controller 方法信息不能能
作用范围所有请求可配置拦截路径
相当于 Laravel全局中间件路由中间件
常见用途编码、CORS、日志、Security 过滤链登录校验、权限校验、性能监控

判断标准:需要「按 URL 配置 + 拿 Controller 信息」用 Interceptor;需要「拦所有请求、最底层」用 Filter。

最直观的理解

Filter 在 DispatcherServlet 之前跑(还没进 Spring MVC);Interceptor 在 DispatcherServlet 找到控制器之后、执行前后跑。Laravel 里所有中间件都在 Kernel 之后按路由分发,而 Spring 把「拦全局」和「拦路由」分成了两层。

HandlerInterceptor:对应路由中间件 ​

实现拦截器 ​

java
package com.example.demo.common;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        String token = request.getHeader("Authorization");
        if (token == null || token.isBlank()) {
            response.setStatus(401);
            return false;                       // 拦截,请求终止
        }
        return true;                            // 放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
                           Object handler, ModelAndView modelAndView) {
        // 控制器执行后、视图渲染前(类似中间件 after)
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) {
        // 请求完成后(可用于记录耗时)
    }
}

三个方法的时机对照:

方法时机类比 Laravel
preHandle进入控制器前中间件 before
postHandle控制器返回后、视图渲染前中间件 after
afterCompletion整个请求结束后terminate

注册拦截器(关键:要显式注册才生效) ​

java
package com.example.demo.config;

import com.example.demo.common.AuthInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    public WebConfig(AuthInterceptor authInterceptor) {
        this.authInterceptor = authInterceptor;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")          // 拦这些路径
                .excludePathPatterns("/api/login");  // 放行这些
    }
}

和 Laravel 的差异

Laravel 中间件在 Kernel 里注册、可分配给路由;Spring 拦截器注册在配置类里,按 URL 模式匹配。不能像 Laravel 那样给某个控制器方法单独挂中间件,只能按路径前缀拦(配合 @RequestMapping 的组织方式)。

Filter:对应全局中间件 ​

实现 jakarta.servlet.Filter(注意是 3.x 的 jakarta 命名空间):

java
package com.example.demo.config;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        System.out.println("每个请求都经过这里: " + req.getRequestURI());
        chain.doFilter(request, response);        // 放行
    }
}

@Component 注册的 Filter 默认对所有 URL 生效,相当于 Laravel 里放进 $middleware 数组的全局中间件。

也可以注册到指定 URL:

java
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
    FilterRegistrationBean<CorsFilter> reg = new FilterRegistrationBean<>();
    reg.setFilter(new CorsFilter());
    reg.addUrlPatterns("/api/*");
    reg.setOrder(1);          // 顺序
    return reg;
}

执行顺序 ​

Filter 1 → Filter 2 → DispatcherServlet → Interceptor.preHandle
         → 控制器 → Interceptor.postHandle → Filter 后置逻辑
  • Filter 按 @Order / 注册顺序执行
  • Interceptor 按注册顺序执行,preHandle 顺序执行,postHandle 逆序执行

注意

CORS 一定要用 Filter(拦截器可能被 Spring Security 拦在后面);登录/权限校验用 Interceptor。Spring Security 自己有独立的过滤器链(见 Spring Security 深入),和 Interceptor 是两条路。

典型场景选型 ​

需求选 Filter选 Interceptor
CORS 跨域✅
请求日志 / 耗时✅
字符编码✅
登录校验✅
权限校验(拿用户角色)✅
请求参数篡改校验✅
限流✅

拦截器里如何传递数据给控制器 ​

Laravel 中间件可以往 $request 里塞数据;Spring 拦截器可以用 request.setAttribute:

java
// preHandle 里
request.setAttribute("currentUser", user);

// 控制器里
@GetMapping("/me")
public User me(@RequestAttribute("currentUser") User user) {
    return user;
}

TIP

@RequestAttribute 专门读取 request.setAttribute 塞进去的数据。登录信息从拦截器传到控制器,这是标准做法。

与 Laravel 中间件对比总结 ​

维度LaravelSpring
全局拦截Kernel $middlewareFilter
按路由拦截中间件赋给路由Interceptor + 路径匹配
注册方式Kernel 数组 / 路由方法WebMvcConfigurer.addInterceptors
放行return $next($request)return true(pre)或 chain.doFilter(...)
终止返回响应return false + 手动写状态码
拿控制器信息拿不到handler 参数里有方法对象

下一节,拦截器的兄弟 —— 参数校验:数据校验。

面向 PHP / Laravel 开发者的 Spring Boot 中文文档