如何在自定义JSP错误页面中查看并显示异常信息和状态码?

问题描述 投票:0回答:2

我知道我可以像这样在 web.xml 中添加一些内容

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

然而,jsp 页面不会显示任何建设性信息,因为它无法获取异常到底是什么。我知道我们可以通过各种

exception-type
将不同的异常转发到不同的页面,但是在 web.xml 中编写的内容太多了。我希望一页就足够了,另一页可以处理 404 之类的错误。

那么应该如何将异常信息传递到jsp页面呢?使用会话?

理想的情况可能是页面获取异常信息并显示一些相关消息,而不向用户透露异常。相反,它可以将其记录到文件中以供将来参考。实现这一目标的最佳方法是什么?谢谢。

jsp custom-error-pages
2个回答
13
投票

有关异常的信息已经可通过多个请求属性获得。您可以在 the

RequestDispatcher
javadoc:

中找到所有这些属性的名称

所以,简而言之,这个 JSP 示例应该显示所有可能的异常详细信息:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<ul>
    <li>Exception: <c:out value="${requestScope['javax.servlet.error.exception']}" /></li>
    <li>Exception type: <c:out value="${requestScope['javax.servlet.error.exception_type']}" /></li>
    <li>Exception message: <c:out value="${requestScope['javax.servlet.error.message']}" /></li>
    <li>Request URI: <c:out value="${requestScope['javax.servlet.error.request_uri']}" /></li>
    <li>Servlet name: <c:out value="${requestScope['javax.servlet.error.servlet_name']}" /></li>
    <li>Status code: <c:out value="${requestScope['javax.servlet.error.status_code']}" /></li>
</ul>

此外,您还可以展示这些有用的信息:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<jsp:useBean id="date" class="java.util.Date" />
...
<ul>
    <li>Timestamp: <fmt:formatDate value="${date}" type="both" dateStyle="long" timeStyle="long" /></li>
    <li>User agent: <c:out value="${header['user-agent']}" /></li>
</ul>

当您将页面标记为错误页面时,具体的

Exception
实例本身在 JSP 中仅可用作
${exception}

<%@ page isErrorPage="true" %>
...
${exception}

仅当您使用 EL 2.2 或更高版本时,您才可以打印其堆栈跟踪,如下所示:

<%@ page isErrorPage="true" %>
...
<pre>${pageContext.out.flush()}${exception.printStackTrace(pageContext.response.writer)}</pre>

或者,如果您尚未使用 EL 2.2,则为此创建一个 自定义 EL 函数

public final class Functions {

    private Functions() {}

    public static String printStackTrace(Throwable exception) {
        StringWriter stringWriter = new StringWriter();
        exception.printStackTrace(new PrintWriter(stringWriter, true));
        return stringWriter.toString();
    }

}

注册于

/WEB-INF/functions.tld

<?xml version="1.0" encoding="UTF-8" ?>
<taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <display-name>Custom Functions</display-name>    
    <tlib-version>1.0</tlib-version>
    <uri>http://example.com/functions</uri>

    <function>
        <name>printStackTrace</name>
        <function-class>com.example.Functions</function-class>
        <function-signature>java.lang.String printStackTrace(java.lang.Throwable)</function-signature>
    </function>
</taglib>

并且可以用作

<%@ taglib prefix="my" uri="http://example.com/functions" %>
...
<pre>${my:printStackTrace(exception)}</pre>

对于异常的日志记录,最简单的地方是filter,它映射到

/*
的URL模式上,并且基本上执行以下操作:

try {
    chain.doFilter(request, response);
} catch (ServletException e) {
    log(e.getRootCause());
    throw e;
} catch (IOException e) { // If necessary? Usually not thrown by business code.
    log(e);
    throw e;
}

0
投票

是的,在我看来,会话是存储与当前请求相关的异常的好地方。

处理完异常后不要忘记清除它。

此外,您还可以将错误代码从支持代码传递到表示层,而不是异常,在表示层中可以使用属性文件将其转换为某种对用户而言意味着完全错误的代码。

© www.soinside.com 2019 - 2024. All rights reserved.