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

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

场景:
在过滤器中判断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响应。

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果`doGetAuthenticationInfo`方法抛出的自定义异常无法全局异常处理捕获,可能是因为全局异常处理没有正确配置或者没有被正确调用。以下是一些可能的原因和解决方法: 1. 检查全局异常处理的配置是否正确。在web.xml文件,需要正确配置全局异常处理的名称和类名,例如: ```xml <filter> <filter-name>GlobalExceptionHandler</filter-name> <filter-class>com.example.GlobalExceptionHandler</filter-class> </filter> <filter-mapping> <filter-name>GlobalExceptionHandler</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` 其,`filter-name`指定了全局异常处理的名称,`filter-class`指定了全局异常处理的类名。`filter-mapping`用于指定拦截的URL模式。请确保这些配置项正确无误。 2. 确认全局异常处理是否被正确调用。在`doFilter`方法,需要调用`filterChain.doFilter`方法来继续处理请求。如果没有调用该方法,那么请求将不会继续处理,也就无法触发全局异常处理。请确保在`doFilter`方法正确调用了`filterChain.doFilter`方法。 ```java public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException { try { // 执行过滤器链 filterChain.doFilter(req, res); } catch (MyException e) { // 处理自定义异常 e.printStackTrace(); } catch (Exception e) { // 处理其他异常 e.printStackTrace(); } } ``` 3. 确认自定义异常是否正确抛出。在`doGetAuthenticationInfo`方法,需要正确抛出自定义异常,例如: ```java if (user == null) { throw new MyException("User not found!"); } ``` 请确保自定义异常被正确抛出,并且没有被其他异常或错误覆盖。 如果以上方法都无法解决问题,可以尝试使用调试工具来定位问题,例如使用IDE的调试功能来查看异常抛出的堆栈信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值