如何在 JSP 页面中打印错误堆栈跟踪?

Posted

技术标签:

【中文标题】如何在 JSP 页面中打印错误堆栈跟踪?【英文标题】:How can I print error stack trace in JSP page? 【发布时间】:2011-12-29 11:25:06 【问题描述】:

我在 web.xml 中设置了这样的错误页面:

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

现在我想在 JSP 上打印错误堆栈跟踪(当然仅在开发模式下)。如何在我的 JSP 页面上打印错误堆栈跟踪?我没有为此应用程序使用任何框架,因此我的程序只能使用默认的 servlet API。

【问题讨论】:

【参考方案1】:

在错误页面上,只需:

<jsp:scriptlet>
    exception.printStackTrace(response.getWriter())
</jsp:scriptlet>

尽管这引出了一个问题:用户将如何处理异常。为什么不将异常写入错误日志,这样它就会被持久化,并且在用户抱怨后您可以返回它呢?

【讨论】:

【参考方案2】:

抛出的异常对象可用作名称为“javax.servlet.error.exception”的请求属性。因此,在您的 JSP 中,您可以编写:

<% request.getAttribute("javax.servlet.error.exception").printStackTrace(new java.io.PrintWriter(out); %>

【讨论】:

【参考方案3】:

从内部设置的request中获取参数,用于打印和处理causemessage等其他信息

<c:set var="exception" value="$requestScope['javax.servlet.error.exception']"/>

并打印堆栈跟踪

<!-- Stack trace -->
<jsp:scriptlet>
  exception.printStackTrace(new java.io.PrintWriter(out));
</jsp:scriptlet>

另见

JSPIntro4 - Handling Errors

【讨论】:

我们如何使用 "" ?它给出编译(jsp解析)异常 @gtiwari333 您需要在顶部添加&lt;%@page pageEncoding="UTF-8" isErrorPage="true" %&gt; 才能启用此功能。【参考方案4】:

可能对你有帮助.. 它将在浏览器中显示异常 StackTrace

exception.printStackTrace(response.getWriter());  

或者

<%
  try
     int test = Integer.parseInt("hola");
  catch(Exception e)
     **// HERE THE MAGIC BEGINS!!**
     out.println("<div id=\"error\">");
     e.printStackTrace(new java.io.PrintWriter(out));
    out.println("</div>");
    **// THE MAGIC ENDS!!**
  
%>

如果您在 error.jsp 顶部声明 &lt;% page isErrorPage="true" %&gt;,那么您可以访问由 $exception 抛出的异常(以及所有的 getter)

<p>Message: $exception.message  

查看更多..Mapping Errors to Error Screens

【讨论】:

【参考方案5】:

请求转发到错误页面时,容器会设置以下参数。

javax.servlet.error.status_code javax.servlet.error.exception javax.servlet.error.message javax.servlet.error.request_uri javax.servlet.error.servlet_name javax.servlet.error.exception_type

在你的错误 JSP 中这样做,

<%request.getAttribute("javax.servlet.error.exception").printStackTrace(new java.io.PrintWriter(out))%>;

否则如果您的错误页面被定义为带有Page Directive之类的错误页面,

<%@ page isErrorPage="true" import="java.io.*"%>

exception 脚本变量将在 JSP 中声明。您可以使用 scriptlet 打印脚本变量,

exception.printStackTrace(new java.io.PrintWriter(out));

或者,

<jsp:scriptlet>
    exception.printStackTrace(response.getWriter())
</jsp:scriptlet>

【讨论】:

如果使用facelets你可以#requestScope['javax.servlet.error.status_code']【参考方案6】:

可以使用jstl核心库

1) 在 JSP 文件之上导入 tablib

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

2) 使用标签

<c:catch var="myExceptionObject">
    Code that might throw Exception
</c:catch>

<c:if test="$myExceptionObject != null">
    There was an exception: $myExceptionObject.message
</c:if>

【讨论】:

【参考方案7】:

或者,为了避免在您的 jsp 中使用 scriptlet,请使用 jstl:

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
...

<c:set var="exception" value="$requestScope['javax.servlet.error.exception']"/>

<c:if test="$exception != null">
  <h4>$exception</h4>
  <c:forEach var="stackTraceElem" items="$exception.stackTrace">
    <c:out value="$stackTraceElem"/><br/>
  </c:forEach>
</c:if>

理想情况下,不应将 scriptlet 作为最佳实践。通过 web.xml 配置显式阻止 jsp 文件中的脚本:

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <scripting-invalid>true</scripting-invalid>
  </jsp-property-group>
</jsp-config>

【讨论】:

【参考方案8】:

十年来,使用 JSP scriptlets 是一种不受欢迎的做法。你最好avoid它。

如果您已经使用 EL 2.2 或更新版本(Tomcat 7+、JBoss AS 6+、WildFly、GlassFish 3+ 等),并且对 $instance.method() 形式的方法表达式提供了新支持,那么您可以使用100% EL 为此。

首先,您需要通过JspWriter#flush() 显式刷新 JSP 编写器,以便所有前面的 JSP 模板输出真正写入 servlet 响应的编写器:

$pageContext.out.flush()

那么你可以将ServletResponse#getWriter() 传递给Throwable#printStackTrace()

$exception.printStackTrace(pageContext.response.writer)

完整示例:

<%@page pageEncoding="UTF-8" isErrorPage="true" %>
...
<pre>$pageContext.out.flush()$exception.printStackTrace(pageContext.response.writer)</pre>

如果您已经使用 EL 3.0(Tomcat 8+、WildFly、GlassFish 4+ 等),您甚至可以使用分隔 EL 语句的新分号运算符使其成为单个表达式:

<%@page pageEncoding="UTF-8" isErrorPage="true" %>
...
<pre>$pageContext.out.flush();exception.printStackTrace(pageContext.response.writer)</pre>

如果您由于某种原因不能使用isErrorPage="true"(因此$exception 隐式对象不可用),则只需替换为$requestScope['javax.servlet.error.exception']

<%@page pageEncoding="UTF-8" %>
...
<pre>$pageContext.out.flush()$requestScope['javax.servlet.error.exception'].printStackTrace(pageContext.response.writer)</pre>

如果您还没有使用 EL 2.2,那么最好的办法是创建自定义 EL 函数。详情可见What is the good approach to forward the exception from servlets to a jsp page?

下面是一个更完整的错误页面示例,其中包含更多细节:

<%@page pageEncoding="UTF-8" isErrorPage="true" %>
<%@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>
    <li>Stack trace: <pre>$pageContext.out.flush()$exception.printStackTrace(pageContext.response.writer)</pre></li>
</ul>

【讨论】:

我遇到的一个问题是有时堆栈跟踪会包含 JSP 行。这些在浏览器中被解释为 html。有没有办法逃避堆栈跟踪? (通常我会使用 c:out 但这不适用于这种情况。)【参考方案9】:

在 error.jsp 中添加以下行

<%Logger log = Logger.getLogger("error_jsp.class");
Exception e = (Exception)request.getAttribute("javax.servlet.error.exception");
log.debug(request.getAttribute("javax.servlet.error.message"));
e.printStackTrace();
log.debug(e.getStackTrace());%>

【讨论】:

以上是关于如何在 JSP 页面中打印错误堆栈跟踪?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 .NET 中毫无例外地打印当前的堆栈跟踪?

如何在 Nest.js 中参考打字稿源打印堆栈跟踪

如何让logrus打印堆栈的pkg /错误

如何使用带有行号信息的 gcc 获取 C++ 的堆栈跟踪?

如何打印 C++ 中捕获的异常的堆栈跟踪和 C++ 中的代码注入

如何将堆栈跟踪打印到控制台/登录 Cocoa?