Java 附加到先前输出的JSP错误页

Java 附加到先前输出的JSP错误页,java,jsp,Java,Jsp,我有一个SpringMVC项目,我使用控制器建议来处理控制器中抛出的错误。但是,如果JSP文件中发生错误,我还希望显示一个漂亮的错误页面(即使这真的不应该发生!)。因此,我在项目的web.xml文件中添加了以下内容: <error-page> <error-code>500</error-code> <location>/WEB-INF/views/application/error/view-error.jsp</locat

我有一个SpringMVC项目,我使用控制器建议来处理控制器中抛出的错误。但是,如果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>

500
/WEB-INF/views/application/error/view-error.jsp
java.lang.Exception
/WEB-INF/views/application/error/view-error.jsp
如果我故意在JSTL中触发一个错误,
view error.jsp
的内容会被很好地呈现出来。但是,内容会附加到发生错误的JSP文件的输出中。例如,如果在第50行的
display users.jsp
中发生错误,则结果是在错误发生之前生成的输出(第1-50行)在
view error.jsp
中的内容前面

这是非常不受欢迎的,因为它会生成一个看起来很怪的错误页面。由于我无法判断异常将被抛出到何处(如果可以,我将修复错误),因此用户看到的很可能看起来很糟糕


我猜这是因为输出已经在缓冲区中,并且可能已经发送到客户端了?我有没有办法解决这个问题,或者有没有其他方法?谢谢

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


这就是为什么不推荐scriplet的原因之一,如果您真的需要在JSP中添加一些智能,那么在将任何内容发送到浏览器之前,它应该位于页面的开头。但理想情况下,一切都应该在servlet中提前计算,并将准备好的数据放入请求属性中。这样,除了HTML输出和请求属性格式副本之外,JSP应该只包含简单的条件或循环标记。生成异常的风险很小。

看起来HttpServletResponse的OutputStream是在enitre JSP完成呈现之前写入的

理想情况下,这应该可以通过“自动刷新”属性进行控制

但以防万一,这是无法解决的:

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

一般的想法是创建一个过滤器,该过滤器将向下面的层传递一个“响应包装器”。此响应包装器保存对真实响应实例的引用。写入响应的任何内容都可以由响应包装器进行操作,然后发送到真正的响应实例

因此,对于您的情况,您可以将所有数据附加到StringBuilder中,然后当控件返回到过滤器时,过滤器可以将整个StringBuilder打印到实际响应的OutputStream中

以下示例截取servlet等编写的任何内容,然后将其gzip版本发送到浏览器:


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

1) 将生成输出的所有JSTL代码放在一个新的JSP中——让我们称之为display-users-view.JSP(可以随意调用)

2) 通过导入从display-users.jsp页面导入display-users-view.jsp,但请确保将内容转储到var(!)。e、 g:

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


注意,通过使用c:import,您不必传递提交到display-users.jsp的任何querystring或form参数,因为您的display-users视图.jsp中仍然可以使用它们。

OP并不表示他正在使用scriptlet。他提到的都是JSTL,所以它可能只是一个简单的
@GriffeyDog。你是对的,我的答案可能太笼统了。但是
中的错误您是正确的,但是,我没有使用Scriptlet。我只使用JSTL。在我的JSP文件中发生的大部分事情是遍历数据以及简单的条件检查——所有这些都是使用JSTL进行的。不幸的是,有些JSP确实发生了稍微复杂一点的事情,而且目前还没有优先考虑重构。这就是为什么我想要这个“安全网”。没有错误的整个页面的大小是9KB,即使我在顶部附近触发了错误,这种情况仍然会发生,所以我不认为这是由HTML的数量引起的。谢谢你的回答!或如果已经提交了响应,则可以让view-error.jsp执行某些操作。也许你在浏览器上执行一个javascript,将其重定向到一个错误页面。非常感谢你的回答,我将对此进行研究!这确实是一个肮脏的解决办法,但它实际上是相当合乎逻辑的。如果找不到更“干净”的解决方案,我会记住这一点。:-)谢谢你的回答,我很感激!另一件事你应该考虑的是:C:FoRobe可以产生大量的空白,这会导致过早的缓冲区提交。有时,为了防止缓冲区提交,您只需要生成大量数据的c:forloop,而不需要JSTL的其余部分。
<c:import url="display-users-view.jsp" var="output"/>
${output}