关于过滤器中的异常不能被全局异常处理器拦截的问题

关于过滤器中的异常不能被全局异常处理器拦截的问题

场景:
在过滤器中判断token是否失效,如果失效则需要抛出指定的异常。

问题:
过滤器抛出的异常不能被自定义异常处理器拦截到,返回不了自定义的格式。

解决办法:

  1. 使用HandlerExceptionResolver将异常交给注册的全局异常处理器来处理。(本篇文章的解决办法)
  2. 另写一个过滤器中捕获chain.doFilter(request, response);中的异常并放入HttpRequest中的Attribute里,然后请求转发到提前写好的controller里,controller需要做的就是将异常取出并将异常抛出交给全局异常处理器处理,还需要注意这个过滤器需在过滤器链中靠前。(仅供参考,未经验证)

完整代码如下:

@Component
public class AuthFilter implements Filter {
    @Value("${jwt.key}")
    private String key;
    @Resource
    private AuthFilterProperties authFilterProperties;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource(name = "handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse res = (HttpServletResponse) servletResponse;
        // 1、过滤请求路径
        String uri = req.getRequestURI();
        if (authFilterProperties.getExcludedPath().contains(uri)) {
            filterChain.doFilter(req, res);
            return;
        }
        // 2、校验token
        String token = req.getHeader("Authorization");
        String userInfo = null;
        try {
            if (StrUtil.isEmpty(token)) {
                throw new ServiceException(ExceptionEnum.TOKEN_EMPTY);
            }
            if (!JWTUtil.verify(token, key.getBytes())) {
                throw new ServiceException(ExceptionEnum.TOKEN_INVALID);
            }
            String userId = (String) JWTUtil.parseToken(token).getPayload("userId");
            if (StrUtil.isEmpty(userId)) {
                throw new ServiceException(ExceptionEnum.TOKEN_INVALID);
            }
            userInfo = stringRedisTemplate.opsForValue().get(RedisPrefixConstant.ACCESS_TOKEN + userId);
            if (StrUtil.isEmpty(userInfo)) {
                throw new ServiceException(ExceptionEnum.TOKEN_EXPIRED);
            }
        } catch (ServiceException e) {
            resolver.resolveException(req, res, null, e);
            return;
        }
        // 3、本地线程添加用户信息
        req.setAttribute("userInfo", userInfo);
        filterChain.doFilter(req, res);
    }
}

Tips:
● 全局异常处理器只能处理Spring MVC里的异常。
● 在过滤器中手动调用 resolver.resolveException(req, res, null, e); 实际上是强制将异常交给了注册的全局异常处理器来处理。这个方法的作用是将异常对象 e 交给 Spring MVC 的异常解析机制来处理,而不是依赖于默认的异常捕获机制。
● 在resolver.resolveException(req, res, null, e)后面加上return是为了确保异常处理后,过滤器链不再继续执行。如果没有return,即使异常被处理,过滤器链仍会继续执行,这可能会导致多次响应,从而在前端看到多次JSON响应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值