Spring 50例常见错误(十四)

文章整理来源:Spring编程常见错误50例_spring_spring编程_bean_AOP_SpringCloud_SpringWeb_测试_事务_Data-极客时间

案例35:不能用 ControllerAdvice 处理过滤器中的异常

        用 ControllerAdvice 试图捕获过滤器中的异常

@WebFilter
@Component
public class PermissionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String token = httpServletRequest.getHeader("token");
        if (!"111111".equals(token)) {
            System.out.println("throw NotAllowException");
            throw new NotAllowException();
        }
        chain.doFilter(request, response);
    }
}
-------------------------------------------------
@RestControllerAdvice
public class NotAllowExceptionHandler {
    @ExceptionHandler(NotAllowException.class)
    @ResponseBody
    public String handle() {
        System.out.println("403");
        return "{\"resultCode\": 403}";
    }
}

        解析:过滤器执行流程图如下

        Spring 在 doDispatch() 执行用户请求时,当在请求对应的 handler 过程中发生异常,就会把异常赋值给 dispatchException,再交给 processDispatchResult() 进行处理。在 processDispatchResult() 中会继续交给 processHandlerException() 方法,选择合适的 HandlerExceptionResolver 进行处理。这里的 handlerExceptionResolvers 包含前面声明的 NotAllowExceptionHandler 的异常处理器的 ExceptionHandlerExceptionResolver 包装类。

        而在 doDispatch() 会先经过 doFilter ,在 Filter 中抛出的异常并不会被 NotAllowExceptionHandler 所处理。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   //省略非关键代码

   try {
      ModelAndView mv = null;
      Exception dispatchException = null;
      try {
         //省略非关键代码
         //查找当前请求对应的 handler,并执行
         //省略非关键代码
      }
      catch (Exception ex) {
         dispatchException = ex;
      }
      catch (Throwable err) {
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   //省略非关键代码

        解决: 在 Filter 注入  HandlerExceptionResolver ,并调用 resolveException() 方法让其自行选择 NotAllowExceptionHandler 进行处理

@WebFilter
@Component
public class PermissionFilter implements Filter {

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String token = httpServletRequest.getHeader("token");
        if (!"111111".equals(token)) {
            System.out.println("throw NotAllowException");
            // HandlerExceptionResolver 的 resolveException() 方法进行处理
            resolver.resolveException(httpServletRequest, httpServletResponse, null, new NotAllowException());
            return;
        }
        chain.doFilter(request, response);
    }
}

案例36:默认 mappedHandler == null 判断条件不成立

        欲定义一个 ExceptionHandlerController 捕获 404 异常

@RestControllerAdvice
public class MyExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handle404() {
        System.out.println("404");
        return "{\"resultCode\": 404}";
    }
}

        解析:在 doDispatch 中先会挑选合适的 mappedHandler ,若没有 则调用 noHandlerFound() 方法。在 noHandlerFound() 方法需要将 throwExceptionIfNoHandlerFound 默认设置为 true 即可,这样就会抛出 NoHandlerFoundException 异常,从而被 doDispatch() 内的 catch 俘获。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //省略非关键代码
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }
         //省略非关键代码
}
--------------------------------------------

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (this.throwExceptionIfNoHandlerFound) {
      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
            new ServletServerHttpRequest(request).getHeaders());
   }
   else {
      response.sendError(HttpServletResponse.SC_NOT_FOUND);
   }
}

        而即使将 throwExceptionIfNoHandlerFound 默认设置为 true, getHandler() 也一定会获取到一个 Handler 来处理当前请求,因为在 getHandler() 中有一个 SimpleUrlHandlerMapping 可以拦截所有路径的请求。mappedHandler == null 判断条件永远不会成立,显然就不可能走到 noHandlerFound(),那么就不会抛出 NoHandlerFoundException 异常,也无法被后续的异常处理器进一步处理

        解决:添加配置,并修改 MyExceptionHandler 的 @ExceptionHandler 为 NoHandlerFoundException 即可

spring.resources.add-mappings=false
spring.mvc.throwExceptionIfNoHandlerFound=true

@ExceptionHandler(NoHandlerFoundException.class)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值