SpringBoot 3.x 过滤器与拦截器实战5 种典型场景下的配置与避坑指南在SpringBoot应用开发中过滤器和拦截器是处理HTTP请求的两大利器。它们看似功能相似实则各司其职适用于不同的业务场景。本文将深入剖析两者的核心差异并通过5个典型场景的实战案例带你掌握它们的正确使用姿势。1. 核心概念与执行机制1.1 过滤器(Filter)的本质特性过滤器是Servlet规范定义的组件其核心特点包括执行时机在请求进入Servlet容器后但尚未到达DispatcherServlet前执行作用范围可修改请求和响应对象如包装HttpServletRequest生命周期由Servlet容器管理与Spring上下文无关// 基础过滤器实现示例 public class BasicFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long start System.currentTimeMillis(); chain.doFilter(request, response); // 关键调用过滤器链 System.out.println(耗时 (System.currentTimeMillis() - start)); } }1.2 拦截器(Interceptor)的核心能力拦截器是Spring MVC的组件具有以下特征执行阶段在DispatcherServlet处理后进入Controller方法前后触发Spring整合可直接注入Spring管理的Bean如Service精细控制能获取处理器的Method对象和参数信息// 拦截器基础实现 public class AuthInterceptor implements HandlerInterceptor { Autowired private AuthService authService; // 可注入Spring Bean Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { return authService.checkToken(request.getHeader(Token)); } }1.3 关键差异对比特性过滤器(Filter)拦截器(Interceptor)规范归属Servlet规范Spring框架依赖注入不支持支持异常处理无法使用ControllerAdvice可被统一异常处理捕获执行顺序最先执行在DispatcherServlet之后请求体访问可多次读取只能读取一次关键提示过滤器适合处理与业务无关的通用逻辑如CORS、编码而拦截器更适合业务相关的处理如权限校验、日志记录2. 认证鉴权场景实战2.1 JWT认证的过滤器实现对于无状态的JWT认证过滤器是理想选择public class JwtFilter extends OncePerRequestFilter { Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException { String token resolveToken(request); if (token ! null jwtProvider.validate(token)) { Authentication auth jwtProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(auth); } chain.doFilter(request, response); } private String resolveToken(HttpServletRequest req) { String bearerToken req.getHeader(Authorization); return bearerToken ! null bearerToken.startsWith(Bearer ) ? bearerToken.substring(7) : null; } }配置要点Bean public FilterRegistrationBeanJwtFilter jwtFilter() { FilterRegistrationBeanJwtFilter bean new FilterRegistrationBean(); bean.setFilter(new JwtFilter()); bean.addUrlPatterns(/api/*); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置最高优先级 return bean; }2.2 权限校验的拦截器方案当需要细粒度权限控制时拦截器更合适public class PermissionInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Method method ((HandlerMethod) handler).getMethod(); RequiredPermission annotation method.getAnnotation(RequiredPermission.class); if (annotation ! null !checkPermission(annotation.value())) { response.sendError(403, 权限不足); return false; } return true; } }典型问题问题拦截器无法获取方法参数详情解决方案结合自定义注解AOP实现参数级权限控制3. 日志记录与性能监控3.1 请求日志的混合方案结合两者优势实现完整日志记录// 过滤器记录基础信息 public class LogFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException { HttpServletRequest req (HttpServletRequest) request; log.info(RequestURI: {}, ClientIP: {}, req.getRequestURI(), req.getRemoteAddr()); chain.doFilter(request, response); } } // 拦截器记录业务信息 public class BizLogInterceptor implements HandlerInterceptor { public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) { log.info(Handler: {}, Status: {}, ((HandlerMethod)handler).getMethod().getName(), response.getStatus()); } }3.2 性能监控的最佳实践public class MetricsInterceptor implements HandlerInterceptor { private ThreadLocalLong startTime new ThreadLocal(); public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { startTime.set(System.currentTimeMillis()); return true; } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { long duration System.currentTimeMillis() - startTime.get(); Metrics.record(request.getRequestURI(), duration); startTime.remove(); } }性能优化技巧使用ThreadLocal避免多线程竞争在afterCompletion中记录确保最终耗时异步上报指标避免阻塞请求线程4. 跨域处理与敏感词过滤4.1 跨域处理的过滤器方案public class CorsFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException { HttpServletResponse response (HttpServletResponse) res; response.setHeader(Access-Control-Allow-Origin, *); response.setHeader(Access-Control-Allow-Methods, POST, GET, OPTIONS); response.setHeader(Access-Control-Max-Age, 3600); response.setHeader(Access-Control-Allow-Headers, Content-Type); chain.doFilter(req, res); } }4.2 敏感词过滤的两种实现方案一过滤器实现全局处理public class SensitiveFilter extends OncePerRequestFilter { private SensitiveWordScanner scanner; protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException { ContentCachingRequestWrapper wrappedRequest new ContentCachingRequestWrapper(request); scanner.scan(wrappedRequest.getParameterMap()); chain.doFilter(wrappedRequest, response); } }方案二拦截器实现业务相关public class SensitiveInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { Method method ((HandlerMethod) handler).getMethod(); if (method.isAnnotationPresent(SensitiveCheck.class)) { // 执行业务相关的敏感词检查 } return true; } }5. 全局异常处理与执行顺序控制5.1 异常处理的差异应对异常类型过滤器中的异常拦截器中的异常preHandle抛出不捕获可被ControllerAdvice处理postHandle抛出不捕获无法被统一异常处理捕获afterCompletion抛出不捕获不推荐在此处抛异常最佳实践// 异常处理过滤器示例 public class ExceptionHandlerFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { try { chain.doFilter(request, response); } catch (Exception e) { // 转换异常为统一响应 ErrorResponse error exceptionConverter.convert(e); response.setStatus(error.getStatus()); response.getWriter().write(objectMapper.writeValueAsString(error)); } } }5.2 执行顺序的精确控制通过实现Ordered接口或使用Order注解// 过滤器顺序控制 Bean Order(1) public FilterRegistrationBeanFilterA filterA() { ... } Bean Order(2) public FilterRegistrationBeanFilterB filterB() { ... } // 拦截器顺序控制 Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(interceptorA).order(1); registry.addInterceptor(interceptorB).order(2); }常见坑点过滤器链中未调用chain.doFilter()导致请求中断拦截器preHandle返回false时未处理响应重复读取请求体导致流关闭全局异常处理对过滤器异常无效6. 高级技巧与性能优化6.1 内容缓存处理解决请求体多次读取问题public class CachingFilter extends OncePerRequestFilter { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException { ContentCachingRequestWrapper requestWrapper new ContentCachingRequestWrapper(request); ContentCachingResponseWrapper responseWrapper new ContentCachingResponseWrapper(response); chain.doFilter(requestWrapper, responseWrapper); // 可在此处访问缓存的响应内容 byte[] responseBody responseWrapper.getContentAsByteArray(); responseWrapper.copyBodyToResponse(); } }6.2 异步请求处理针对异步请求的特殊处理public class AsyncInterceptor implements AsyncHandlerInterceptor { public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) { // 异步请求开始时触发 log.info(Async request started); } }6.3 性能优化建议过滤器优化简单逻辑直接使用Filter避免在过滤器中执行耗时IO操作使用OncePerRequestFilter确保单次执行拦截器优化预处理逻辑尽量放在preHandlepostHandle中避免修改已提交的响应使用Conditional按条件注册拦截器Configuration ConditionalOnProperty(name feature.log.enabled, havingValue true) public class LogInterceptorConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()); } }在实际项目中我曾遇到一个典型的性能问题由于在过滤器中同步记录详细访问日志导致系统吞吐量下降30%。通过将日志改为异步批量写入并移除非关键字段记录最终使系统性能恢复并提升15%。这个案例告诉我们即使在看似简单的组件中性能优化也能带来显著收益。