写点什么

SpringBoot 中的拦截器江湖

  • 2025-05-13
    福建
  • 本文字数:2533 字

    阅读完需:约 8 分钟

前言


很多小伙伴在工作中遇到拦截需求就无脑写 HandlerInterceptor,结果被复杂场景搞得鼻青脸肿。

作为一名有多年开发经验的程序员,今天领大家到 SpringBoot 的山头认认 6 把交椅:



这篇文章以梁山为背景的介绍 SpringBoot 中的拦截器,可能更通俗易懂。


希望对你会有所帮助,记得点赞和收藏。


第一把交椅:Filter


Filter 是梁山中的总寨主。


典型战斗场面:全局鉴权/接口耗时统计


@WebFilter("/*") public class CostFilter implements Filter {    @Override    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {        long start = System.currentTimeMillis();        chain.doFilter(req, res); // 放行江湖令箭        System.out.println("接口耗时:"+(System.currentTimeMillis()-start)+"ms");    }}
复制代码


起义缘由:必须是最高寨主,因为他在 Servlet 容器滚刀肉层面出手。想当年有个兄弟在 Filter 里调用 Spring Bean,结果 NPE 错杀千人(要用 WebApplicationContextUtils 拿 Bean 才是正解)


第二把交椅:HandlerInterceptor


HandlerInterceptor 是梁山中的二当家。


必杀场景:接口权限验证/请求参数自动装填


public class AuthInterceptor implements HandlerInterceptor {    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {        String token = request.getHeader("X-Token");        if(!"vip666".equals(token)){            response.setStatus(403);            return false; // 关门放狗        }        return true;    }}
// 衙门张贴告示@Configurationpublic class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns("/api/**") .excludePathPatterns("/api/login"); }}
复制代码


二当家的雷区

  1. postHandle 里修改了 Response 但内容已提交(注意 response.isCommitted()判断)

  2. 拦截资源请求要配置静态路径排出(例如/exclude/**)

  3. 多拦截器顺序要调准确(Order 值越小越早执行)


第三把交椅:AOP 拦截器


AOP 是梁山中的军师智多星。


运筹帷幄场景:服务层方法缓存/事务管理


@Aspect@Componentpublic class CacheAspect {    @Around("@annotation(com.example.anno.Cacheable)")    public Object aroundCache(ProceedingJoinPoint jp) {        String cacheKey = buildKey(jp);        Object cacheVal = redisTemplate.opsForValue().get(cacheKey);        if(cacheVal != null) return cacheVal;                Object result = jp.proceed();        redisTemplate.opsForValue().set(cacheKey, result, 5, TimeUnit.MINUTES);        return result;    }}
复制代码


军师锦囊

  • 只可拦截 Spring 管理的 Bean(new 的对象拦截不了)

  • 与 Transactional 注解的顺序要注意(建议 AOP 切面 Order 大于事务切面)

  • 自定义注解要写在接口方法上才生效(要是实现类方法需要用 @within)


第四把交椅:RestTemplate 拦截器


RestTemplate 是梁山中的水军头领。


远程战事:统一添加请求头/加密请求参数


public class TraceInterceptor implements ClientHttpRequestInterceptor {    @Override    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) {        request.getHeaders().add("X-TraceId", UUID.randomUUID().toString());        return execution.execute(request, body);    }}
// 注册水军@Bean public RestTemplate restTemplate() { RestTemplate rt = new RestTemplate(); rt.getInterceptors().add(new TraceInterceptor()); return rt;}
复制代码


总督黑历史

  1. 编码问题:body 若是字符串需要自行转字节数组(避免乱码)

  2. 多次拦截:拦截器按添加顺序执行(第一个最后执行)

  3. 访问 HTTPS 需要额外配置 SSL(记得补上 SSLContext)


第五把交椅:Feign 拦截器


Feign 拦截器是梁山中的外交使节。


出使外国:统一签名计算/Header 透传


public class FeignAuthInterceptor implements RequestInterceptor {    @Override    public void apply(RequestTemplate template) {        template.header("Authorization", "Bearer " + SecurityContext.getToken());    }}
// 缔结合约@Configurationpublic class FeignConfig { @Bean public FeignAuthInterceptor feignAuthInterceptor() { return new FeignAuthInterceptor(); }}
复制代码


使节烫手山芋

  • GET 请求 Body 丢失问题(要自己特殊处理)

  • Form 表单参数要手动编码(使用 feign-form 扩展)

  • Path 参数需要 Expression 表达式解析(动态值要用 @Param 注明)


第六把交椅:WebFilter


WebFilter 是梁山中的特种兵。


闪电战场景:响应式编程统一编码/跨域处理


@Componentpublic class CorsWebFilter implements WebFilter {    @Override    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {        ServerHttpResponse response = exchange.getResponse();        response.getHeaders().add("Access-Control-Allow-Origin", "*");        return chain.filter(exchange);    }}
复制代码


作战条件


  • 必须在 WebFlux 环境下(传统 MVC 无效)

  • 响应式编程模式(函数式声明)

  • 非阻塞管道(异步要配合 Mono/Flux)


各派武功排行榜



武林秘笈


1. 顺序就是力量

Filter -> Interceptor -> AOP ,越早拦截越省力(但别在 Filter 里做业务)


2. 量力而行选兵器

  • 简单鉴权用 HandlerInterceptor

  • 方法级管控上 AOP

  • 微服务用 FeignInterceptor


3. 性能损耗要监控

用 Arthas 监控拦截链路耗时,避免拦截器连环夺命 call


# 查看HandlerInterceptor耗时trace *.preHandle '#cost>10' # 诊断AOP切面watch com.example.aop.*Aspect * '{params,returnObj}' -x 3
复制代码


最后送给各位江湖儿女一句话:拦截是门艺术,别让好刀砍了自己人!


文章转载自:苏三说技术

原文链接:https://www.cnblogs.com/12lisu/p/18867841

体验地址:http://www.jnpfsoft.com/?from=001YH

用户头像

还未添加个人签名 2025-04-01 加入

还未添加个人简介

评论

发布
暂无评论
SpringBoot中的拦截器江湖_spring_量贩潮汐·WholesaleTide_InfoQ写作社区