Spring Boot 错误处理

2022-08-31 16:41 阅读

Web中的错误处理,就是在系统抛出异常之后,HTTP响应使用什么状态码,显示什么页面。

默认的处理方式

如果系统中抛出异常,Tomcat会将响应状态码设置成500,并自动生成一个含有错误堆栈信息的页面。

如果想让Tomcat使用其它响应状态码,可以使用Response.sendError(int sc, String msg)改变状态码。

web.xml配置

Tomcat自动生成的页面显然不能够满足异常处理的需要,最常见的一个需求就是,自定义错误处理页面。

可以通过web.xml配置某个响应状态码对应的错误页面。

<error-page>
    <error-code>500</error-code>
    <location>/error.jsp</location>
</error-page>

也可以配置某个异常对应的错误页面。

<error-page>
    <exception-type>java.lang.NullException</exception-type>
    <location>/error.jsp</location>
</error-page>

Spring MVC错误处理

Spring MVC提供了多个HandlerExceptionResolver处理异常。根据以下顺序依次进行处理。

  • SimpleMappingExceptionResolver:可定义异常类型对应的错误页面
  • DefaultHandlerExceptionResolver:处理Spring MVC自己抛出的异常。另外还有ResponseEntityExceptionHandler
  • ResponseStatusExceptionResolver:处理使用@ResponseStatus注解了的异常
  • ExceptionHandlerExceptionResolver:调用@ExceptionHandler方法处理异常

SimpleMappingExceptionResolver

用于定义异常类型和对应的错误页面

<bean id="simpleMappingExceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="org.springframework.dao.DataIntegrityViolationException">data_integrity_violation_exception</prop>
        </props>
    </property>
</bean>

自定义HandlerExceptionResolver

自定以HandlerExceptionResolver处理异常,可返回以下三种结果。

  • 直接返回指向错误页面的ModelAndView
  • 如果错误被解决,则返回空的ModelAndView
  • 如果错误无法处理,则返回null,由下一个HandlerExceptionResolver继续处理

容器错误页面

如果所有的HandlerExceptionResolver都无法处理异常,这个异常将交给Servlet容器处理。可以在web.xml里定义错误页面的地址。

<error-page>
    <location>/error</location>
</error-page>

再定义Controller进行处理:

@RestController
public class ErrorController {
    @RequestMapping(path = "/error")
    public Map<String, Object> handle(HttpServletRequest request) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", request.getAttribute("javax.servlet.error.status_code"));
        map.put("reason", request.getAttribute("javax.servlet.error.message"));
        return map;
    }
}

Spring Boot 错误处理

Spring Boot默认用BasicErrorController处理/error错误。对于浏览器请求,会根据状态码自动对应到相应的模板。如:

  • error/400.html
  • error/403.html
  • error/404.html
  • error/5xx.html

同时会根据DefaultErrorAttributes提供以下数据:

  • timestamp - The time that the errors were extracted
  • status - The status code
  • error - The error reason
  • exception - The class name of the root exception (if configured)
  • message - The exception message (if configured)
  • errors - Any ObjectErrors from a BindingResult exception (if configured)
  • trace - The exception stack trace (if configured)
  • path - The URL path when the exception was raised

Spring Security 错误处理

Spring Security 使用ExceptionTranslationFilter捕获AccessDeniedException异常,由AccessDeniedHandlerImpl处理。

如果没有设置errorPage,则直接调用response.sendError()。否则转发到错误页面。

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response,
            AccessDeniedException accessDeniedException) throws IOException, ServletException {
        if (response.isCommitted()) {
            logger.trace("Did not write to response since already committed");
            return;
        }
        if (this.errorPage == null) {
            logger.debug("Responding with 403 status code");
            response.sendError(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.getReasonPhrase());
            return;
        }
        // Put exception into request scope (perhaps of use to a view)
        request.setAttribute(WebAttributes.ACCESS_DENIED_403, accessDeniedException);
        // Set the 403 status code.
        response.setStatus(HttpStatus.FORBIDDEN.value());
        // forward to error page.
        if (logger.isDebugEnabled()) {
            logger.debug(LogMessage.format("Forwarding to %s with status code 403", this.errorPage));
        }
        request.getRequestDispatcher(this.errorPage).forward(request, response);
    }
咨询
交流群
电话