You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 如何通过Filter/AOP/异常将刷新token加至响应头不打断业务

实现方案

最优方案:基于OncePerRequestFilter实现(无侵入、符合需求)

你之前的实现错误原因是在判断token过期后直接返回了响应,没有放行请求到Controller执行业务逻辑,调整执行顺序即可解决:

  1. 先做token校验,需要刷新的话先生成新token暂存,不要提前返回响应
  2. 先放行请求执行业务逻辑,等Controller处理完成返回后,再把新token写入响应头
  3. 写入响应头的操作不会修改已生成的响应体,完全不影响业务返回格式

代码示例

@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 23:36:00