JSP错误页面附加到上一个输出

时间:2015-04-27 13:12:16

标签: java jsp

我有一个Spring MVC项目,我使用控制器建议来处理控制器中抛出的错误。但是,如果JSP文件中出现错误,我还想显示一个很好的错误页面(即使这确实不应该发生!)。因此,我在项目的web.xml文件中添加了以下内容:

<error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/application/error/view-error.jsp</location>
</error-page>

<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/WEB-INF/views/application/error/view-error.jsp</location>
</error-page>

如果我故意在JSTL中触发错误,则view-error.jsp的内容会正常。但是,内容附加到发生错误的JSP文件的输出。例如,如果在第50行display-users.jsp内发生错误,则结果是错误发生之前生成的输出(第1-50行)前置view-error.jsp中的内容。

这是非常不受欢迎的,因为它会生成一个时髦的错误页面。而且由于我无法分辨抛出异常的位置(如果可以的话,我会修复错误),那么用户看到的内容很可能看起来很糟糕。

我猜是因为输出已经在缓冲区中了,可能已经发送到客户端了?有什么方法可以解决这个问题,或者可能是另一种方法吗?谢谢!

3 个答案:

答案 0 :(得分:1)

这是大型JSP生成大型HTML的问题,其中scriptlet java代码混杂在一起。一旦写入足够的数据,服务器就会提交标题(将它们发送到客户端)并发送页面的开头。此时,您无法再回滚任何内容以获取浏览器已收到(并可能显示)的数据。

这就是为什么不推荐使用scriplet的原因之一,如果你真的需要将一些情报放在JSP上,它应该在页面的开头才能实际发送到浏览器。但理想情况下,所有内容都应该事先在servlet中计算,并将准备好的数据放入请求属性中。这样,除了HTML输出和请求属性再现之外,JSP应该只包含简单的条件或循环标记。所有这些都没有产生异常的风险。

答案 1 :(得分:1)

看起来在enitre JSP完成渲染之前正在写入HttpServletResponse的OutputStream。

理想情况下,这应该由“autoflush”属性控制。 https://tomcat.apache.org/tomcat-5.5-doc/jspapi/javax/servlet/jsp/JspWriter.html

但以防万一它无法解决:

您可以使用HttpServletResponseWrapper方法拦截写入HttpServletResponse的任何内容。

一般的想法是你创建了一个Filter,Filter会将“Response Wrapper”传递给下面的层。此响应包装器包含对实际响应实例的引用。任何写入响应的东西都可以被Response Wrapper操纵,然后发送到真正的Response实例。

因此,对于您的情况,您可以将所有数据附加到StringBuilder中,然后当控件返回到Filter时,Filter可以将整个StringBuilder打印到真实的Response的OutputStream。

这是一个拦截Servlets等所写内容然后将其GZip1版本发送到浏览器的示例:

http://tutorials.jenkov.com/java-servlets/gzip-servlet-filter.html

答案 2 :(得分:0)

去过那里,做到了。在您重新设计之前,这是一个快速而又肮脏的解决方法。

1)将生成输出的所有JSTL代码放在新JSP中 - 让我们将其命名为display-users-view.jsp(无论你想要什么,都可以调用它)。

2)通过&lt; c:import&gt;从display-users.jsp页面导入display-users-view.jsp,但要确保将内容转储到var(!)。 e.g:

<c:import url="display-users-view.jsp" var="output"/>

3)作为display-users.jsp的最后一步,使用简单的方法将输出转储到屏幕:

${output}

现在,如果在$ {output}之前抛出错误..没有坏处,没有犯规,因为你还没有向浏览器输出任何内容。如果没有错误,$ {output}将转储在display-users-view.jsp中生成的HTML。

注意,通过使用c:import,您不必传递任何提交给display-users.jsp的查询字符串或表单参数,因为您仍然可以在display-users-view.jsp中使用它们。