在处理未捕获异常的Servlet中如何修改HttpServletResponse状态码
问题根因
你遇到的状态码无法修改的问题,是两个常见的Servlet规范特性导致的:
- 当web.xml的
<exception-type>规则触发跳转时,Servlet容器已经默认将响应状态设置为500,同时会在请求域中写入RequestDispatcher.ERROR_STATUS_CODE属性记录原始错误状态,后续流程中容器会优先以该属性的值作为最终响应状态,仅调用response.setStatus()不会修改这个属性,会被容器自动覆盖回500 - 如果你的错误页JSP配置了
<%@ page isErrorPage="true" %>指令,JSP容器在渲染页面时会自动把响应状态重置为500,覆盖你之前设置的状态值
解决步骤
第一步:修改异常处理Servlet代码
设置响应状态的同时,同步修改请求域中的ERROR_STATUS_CODE属性,避免容器覆盖:
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); if (throwable instanceof BadRequest400Exception) { int statusCode = HttpServletResponse.SC_BAD_REQUEST; response.setStatus(statusCode); // 同步修改请求域的状态码属性 request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, statusCode); request.getRequestDispatcher("/WEB-INF/views/error-pages/error-page-400.jsp").forward(request, response); return; } if (throwable instanceof NotFound404Exception) { int statusCode = HttpServletResponse.SC_NOT_FOUND; response.setStatus(statusCode); request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, statusCode); request.getRequestDispatcher("/WEB-INF/views/error-pages/error-page-404.jsp").forward(request, response); return; } // 其他异常处理逻辑 }
注意:不要在该场景下调用
response.sendError(),该方法会触发容器重新匹配error-page规则,反而会导致状态码被重置、甚至出现循环跳转的问题,仅使用response.setStatus()即可。
第二步:调整错误页JSP配置
检查所有错误页JSP的头部page指令:
- 如果不需要用到JSP的异常内置对象,直接删除
isErrorPage="true"属性即可 - 如果需要保留该属性,在JSP顶部追加状态码设置代码:
<%-- 以400错误页为例,对应修改为当前页面的状态码即可 --%> <%@ page isErrorPage="true" %> <% response.setStatus(HttpServletResponse.SC_BAD_REQUEST); %>
内容的提问来源于stack exchange,提问作者torez233
相关产品推荐
相关产品推荐

