java - 将不同的状态码绑定到处理未捕获异常的 servlet 中的 HttpServletResponse
问题描述
在我的项目中,我定义了几种类型的异常,它们应该映射到相应的响应状态代码
// map to status code 400
public class BadRequest400Exception extends RuntimeException {}
// map to status code 401
public class Unauthorized401Exception extends RuntimeException {}
// map to status code 404
public class NotFound404Exception extends RuntimeException {}
请注意,我不想在抛出它们的原始 servlet 中捕获这些异常。这就是为什么我不检查它们。换句话说,我不想拥有这样的东西
public class BusinessLogicServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
// some business logic
throw new Unauthorized401Exception();
} catch (Exception e) {
resp.sendError(401, "...");
}
}
这实际上违背了我在一个中心位置一起处理这些运行时异常的最初目的。为此,我定义了一个专门的 servlet 来处理所有抛出的未捕获异常。它将根据异常类型将请求转发到适当的错误页面
网页.xml:
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/exception</location>
</error-page>
<!-- ... -->
<servlet>
<servlet-name>ExceptionCentralProcessingServlet</servlet-name>
<servlet-class>foo.bar.baz.ExceptionCentralProcessingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ExceptionCentralProcessingServlet</servlet-name>
<url-pattern>/WEB-INF/exception</url-pattern>
</servlet-mapping>
ExceptionCentralProcessingServlet:
public class ExceptionCentralProcessingServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if (throwable instanceof BadRequest400Exception) {
// I want to change status code from 500 to 400 in this case
// which is not working
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
// also not working
// response.sendError(HttpServletResponse.SC_BAD_REQUEST);
request
.getRequestDispatcher("/WEB-INF/views/error-pages/error-page-400.jsp")
.forward(request, response);
return;
}
if (throwable instanceof NotFound404Exception) {
// I want to change status code from 500 to 404 in this case
// which is not working
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
// also not working
// response.sendError(HttpServletResponse.SC_NOT_FOUND);
request
.getRequestDispatcher("/WEB-INF/views/error-pages/error-page-404.jsp")
.forward(request, response);
return;
}
}
}
当我测试它时,这似乎是部分工作。当从 servlet 抛出 BadRequest400Exception 时,请求被转发到 error-page-400.jsp。但是,响应状态码仍然是500
,尽管我已经通过response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
. 根据javax.servlet.http.HttpServlet 中的更改响应代码,这应该可以工作,但实际上并没有成功。我也尝试了另一种方法sendError
:response.sendError(400)
但这也行不通。
我想知道如何将 http 状态代码(默认值似乎是 500)更改为 servlet 中为<exception-type>
处理从其他 servlet 抛出的未捕获异常声明的其他值。
谢谢
解决方案
如果您的目标是在主 servlet 之外的集中位置捕获和处理异常,则更简单的方法可能是使用filter。过滤器能够更改响应状态代码。
一个非常基本的示例如下所示:
public class ExceptionFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// nothing to do
}
@Override
public void destroy() {
// nothing to do
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
try {
chain.doFilter(request, response);
} catch BadRequest400Exception e) {
// however you want to handle this exception
} catch Unauthorized401Exception e) {
// however you want to handle this exception
}
// etc...
}
}
请注意,您还需要filter-mapping
在web.xml
.
在本例中,过滤器只是简单地“包装”了 servlet 请求/响应。任何从 servlet 抛出的未捕获异常都可以通过过滤器中的 try/catch 捕获,例如设置响应状态代码、转发到 JSP、写入日志等。
推荐阅读
- excel - 在导出到 Excel 之前删除表格的额外列
- xml - 如何找到 OPENXML 函数的正确路径
- git - 如何有效地将用户添加到 GitLab 中的所有项目(以编程方式或其他方式)
- amazon-web-services - 项目构建错误:com.amazonaws:aws-java-sdk-secretsmanager:jar 的“dependencies.dependency.version”缺失
- php - 来自 PHP 的 Mysqldump 大表
- python - 在 utf-8 中编码 json 并上传到 Amazon S3
- postgresql - 在 PostgreSQL 中执行动态查询字符串
- internet-explorer-11 - IE11 和 nomodule 属性
- sql - 在 CONCAT 内将 varchar 值转换为 int 时转换失败
- jquery - jquery在父级中找到下一个但不完全是下一个