Spring Boot 如何通过Filter/AOP/异常将刷新token加至响应头不打断业务
实现方案
最优方案:基于OncePerRequestFilter实现(无侵入、符合需求)
你之前的实现错误原因是在判断token过期后直接返回了响应,没有放行请求到Controller执行业务逻辑,调整执行顺序即可解决:
- 先做token校验,需要刷新的话先生成新token暂存,不要提前返回响应
- 先放行请求执行业务逻辑,等Controller处理完成返回后,再把新token写入响应头
- 写入响应头的操作不会修改已生成的响应体,完全不影响业务返回格式
代码示例
@Component public class AutoRefreshTokenFilter extends OncePerRequestFilter { @Resource private TokenUtils tokenUtils; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String oldAccessToken = request.getHeader("Assess-Token"); String newAccessToken = null; try { // 前置逻辑:判断token是否过期,过期则生成新token暂存 if (StrUtil.isNotBlank(oldAccessToken) && tokenUtils.isExpired(oldAccessToken)) { newAccessToken = tokenUtils.refreshToken(oldAccessToken); } // 放行请求,正常执行Controller业务逻辑 filterChain.doFilter(request, response); } finally { // 后置逻辑:不管业务是否抛出异常,都把新token写入响应头 if (StrUtil.isNotBlank(newAccessToken)) { response.setHeader("Assess-Token", newAccessToken); } } } // 若使用Spring Security,配置过滤器顺序为认证过滤器之后 @Override public int getOrder() { return SecurityProperties.DEFAULT_FILTER_ORDER + 1; } }
备选方案:基于AOP实现
如果不想新增过滤器,也可以通过Controller环绕通知实现,侵入性同样很低:
@Aspect @Component public class TokenRefreshAspect { @Resource private TokenUtils tokenUtils; @Resource private HttpServletResponse response; @Around("execution(* com.xxx.controller.*.*(..))") public Object around(ProceedingJoinPoint point) throws Throwable { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String oldAccessToken = request.getHeader("Assess-Token"); String newAccessToken = null; if (StrUtil.isNotBlank(oldAccessToken) && tokenUtils.isExpired(oldAccessToken)) { newAccessToken = tokenUtils.refreshToken(oldAccessToken); } // 执行业务逻辑拿到返回值 Object result = point.proceed(); // 写入响应头 if (StrUtil.isNotBlank(newAccessToken)) { response.setHeader("Assess-Token", newAccessToken); } // 原封不动返回业务响应体 return result; } }
注意事项
- 不要在token校验阶段直接调用
response.getWriter()输出内容,会提前终止请求链路 - 如果刷新token需要用户身份信息,确保过滤器/AOP执行顺序在认证逻辑之后,能拿到正常的用户上下文
- 若响应已经提交(比如接口中主动调用了
response.flushBuffer()),再写入header会失效,业务代码中要避免提前提交响应
内容的提问来源于stack exchange,提问作者Aruix
相关产品推荐
相关产品推荐

