💡 前言
在开发 Web 应用时,我们经常需要对所有请求进行统一处理,例如:
- 记录请求日志
- 实现跨域(CORS)
- 接口权限控制
- 请求参数预处理
- 防止 XSS 攻击
这些功能如果都写在每个 Controller 或 Service 里,不仅代码冗余,还难以维护。
幸运的是,Spring Boot 提供了两种强大的拦截机制:
- Filter(过滤器)
- Interceptor(拦截器)
本文将重点讲解 如何在 Spring Boot 中使用 WebFilter
实现全局的请求过滤逻辑,并结合实际案例带你掌握 Filter 的高级用法。
🧪 一、什么是 WebFilter?
✅ 定义:
WebFilter
是 Java Servlet 标准中的一个接口,用于在请求到达 Controller 之前或响应返回客户端之前执行一些通用操作。
它属于 Servlet 过滤器,比 Spring 的拦截器更早介入请求流程。
✅ 生命周期:
Filter 的生命周期由 Servlet 容器管理,主要包括三个阶段:
- init() 初始化方法,在 Web 应用启动时调用一次。
- doFilter() 核心方法,每次请求都会经过此方法。
- destroy() 销毁方法,在应用关闭时调用。
🛠️ 二、Spring Boot 中配置 WebFilter 的方式
方式一:通过 @WebFilter 注解 + @ServletComponentScan(不推荐)
@WebFilter("/*")
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("【Filter】请求开始:" + ((HttpServletRequest) request).getRequestURI());
chain.doFilter(request, response);
System.out.println("【Filter】请求结束");
}
}
然后在主类上添加:
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
📌 缺点:
- 不支持依赖注入(如注入 Service、Mapper 等)
- 无法灵活控制顺序和路径匹配
方式二:注册 FilterRegistrationBean(推荐)
这是 Spring Boot 官方推荐的方式,支持依赖注入,并且可以灵活控制 Filter 的顺序、URL 模式等。
示例:自定义日志记录 Filter
@Component
public class RequestLoggingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String uri = httpRequest.getRequestURI();
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long duration = System.currentTimeMillis() - startTime;
logger.info("请求 URI: {}, 耗时: {} ms", uri, duration);
}
}
注册 Filter:
@Configuration
public class FilterConfig {
@Autowired
private RequestLoggingFilter requestLoggingFilter;
@Bean
public FilterRegistrationBean<RequestLoggingFilter> loggingFilterRegistration() {
FilterRegistrationBean<RequestLoggingFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(requestLoggingFilter);
registration.addUrlPatterns("/*"); // 所有请求都经过该过滤器
registration.setOrder(1); // 设置优先级,数字越小越先执行
return registration;
}
}
🎯 三、WebFilter 典型应用场景实战
✅ 场景一:请求日志记录(已演示)
适用于记录请求 URL、IP、耗时、用户信息等,便于排查问题和性能分析。
✅ 场景二:跨域请求处理(CORS)
如果你不想使用 @CrossOrigin
注解逐个设置接口跨域,也可以统一在 Filter 中处理:
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
✅ 场景三:防止 XSS 攻击
可以通过重写 getParameter()
方法来清理用户输入,避免脚本注入攻击。
public class XssFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(request);
filterChain.doFilter(xssRequest, response);
}
}
其中 XssHttpServletRequestWrapper
是一个继承 HttpServletRequestWrapper
的包装类,用于对参数进行转义处理。
✅ 场景四:限流与防刷接口
结合 Redis,我们可以实现简单的请求频率限制:
String ip = request.getRemoteAddr();
String key = "request_limit:" + ip;
Long count = redisTemplate.opsForValue().increment(key, 1);
if (count != null && count > 100) {
response.getWriter().write("{\"code\":429,\"message\":\"请求过于频繁\"}");
return;
}
redisTemplate.expire(key, 1, TimeUnit.MINUTES);
🧭 四、Filter vs Interceptor 对比
功能 | Filter | Interceptor |
---|---|---|
所属框架 | Servlet 标准 | Spring MVC |
可否注入 Spring Bean | ❌ 默认不行(除非手动注册为 Bean) | ✅ 可以注入 |
可否访问 Controller 方法 | ❌ 不能获取方法名、注解等 | ✅ 可以获取 |
是否支持 AOP | ❌ | ✅ |
执行时机 | 更早于 Interceptor | |
适用场景 | 跨域、日志记录、XSS、限流 | 登录校验、权限控制、接口埋点 |
📌 建议:
- 如果只是做一些通用的请求拦截(如日志、跨域),推荐使用 Filter;
- 如果要根据业务逻辑做精细控制(如登录验证、权限判断),推荐使用 Interceptor。
📘 五、总结对比表@
内容 | 说明 |
---|---|
Filter 类型 | Servlet 标准,非 Spring 特有 |
注册方式 | 使用 FilterRegistrationBean 最佳实践 |
执行顺序 | 多个 Filter 按 setOrder() 顺序执行 |
典型用途 | 日志记录、跨域处理、XSS 防御、限流 |
优点 | 统一处理所有请求,解耦业务逻辑 |
缺点 | 无法直接使用 Spring IOC 容器中的 Bean(需额外封装) |
🎁 六、结语
Filter 是构建健壮、安全、可维护的 Spring Boot 应用中不可或缺的一环。通过合理使用 WebFilter,你可以轻松实现跨域、日志记录、请求过滤、安全防护等功能,提升系统的稳定性和安全性。
无论你是开发企业级后台系统,还是搭建对外 API 平台,都应该掌握 Filter 的使用技巧。
🎯 点赞、收藏、转发本文,让更多开发者受益!