Spring Boot 2.0.1 WAR部署Tomcat8.5时BasicErrorController异常问题
我之前也踩过这个坑,尤其是用Spring Boot 2.x WAR包部署到外部Tomcat时,500错误总是跳Tomcat自带的页面,而不是Spring Boot的白标页或者自定义错误页。核心原因其实是外部Tomcat的错误处理机制抢在了Spring Boot的BasicErrorController前面。下面结合你的两种方案,给你具体的排查和解决步骤:
先搞懂为什么会这样?
当你把Spring Boot做成WAR包部署到外部Tomcat时,Tomcat作为Servlet容器会先接管所有错误请求。如果错误没有被Spring MVC的DispatcherServlet处理到(比如异常发生在Filter层、Servlet初始化阶段,或者Spring的错误处理没覆盖到),Tomcat就会直接返回它自己的默认错误页面,这就是你看到的500异常的问题。
针对你的两种方案的修复方案
方案1:保留默认BasicErrorController,让它接管所有错误
如果想继续用Spring Boot默认的白标错误页,你需要让Tomcat把所有错误都转发到Spring的/error端点(也就是BasicErrorController的处理路径):
- 添加web.xml配置(因为Spring Boot WAR默认没有web.xml,你需要在
src/main/webapp/WEB-INF下创建一个):
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- 把所有错误码和异常都转发到Spring的/error端点 --> <error-page> <error-code>404</error-code> <location>/error</location> </error-page> <error-page> <error-code>500</error-code> <location>/error</location> </error-page> <error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error</location> </error-page> </web-app>
这个配置会让Tomcat把所有404、500以及任意Throwable类型的异常,都转发到Spring Boot的/error接口,这样BasicErrorController就能处理并返回默认的白标页了。
- 检查Spring Boot配置:
确保application.properties里没有关闭白标错误页:
server.error.whitelabel.enabled=true # 默认就是true,别改成false
方案2:自定义ErrorViewResolver的情况下,确保覆盖所有错误场景
如果用了自定义的ErrorViewResolver,除了确保代码能处理500状态码,还要配合上面的web.xml配置,让Tomcat把错误都转发过来。另外,检查你的ErrorViewResolver代码是否覆盖了500的情况:
比如修正后的自定义Resolver代码:
@Component public class CustomErrorViewResolver implements ErrorViewResolver { @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { // 明确处理500内部错误 if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { ModelAndView mav = new ModelAndView("error/500"); // 对应你的500视图路径 mav.addAllObjects(model); // 把错误信息传递到视图 return mav; } // 处理404 if (HttpStatus.NOT_FOUND.equals(status)) { ModelAndView mav = new ModelAndView("error/404"); mav.addAllObjects(model); return mav; } // 其他错误交给默认处理(比如返回白标页) return new ModelAndView("error/default", model); } }
同时,确保你的视图文件存在(比如用Thymeleaf的话,src/main/resources/templates/error/500.html要存在)。
额外排查点
如果上面的配置还是不行,你可以检查:
- 是否有自定义Filter在抛出异常时没有被Spring捕获?如果Filter里的异常没处理,会直接抛给Tomcat,这时候需要在Filter里手动转发到
/error:
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(request, response); } catch (Exception e) { // 把异常传递给Spring的错误处理 request.setAttribute("javax.servlet.error.exception", e); request.getRequestDispatcher("/error").forward(request, response); } }
- 检查Tomcat的
web.xml(Tomcat安装目录下的conf/web.xml)是否有全局的error-page配置,可能会覆盖你的应用配置,如果有的话,可以注释掉或者调整优先级。
内容的提问来源于stack exchange,提问作者rfran

