5

我在 web.xml 中定义了以下内容:

<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/shared/errors/DefaultErrorPage.xhtml</location>
</error-page>
<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/shared/errors/ViewExpired.xhtml</location>
</error-page>

我还在 faces-config.xml 中使用来自 Omnifaces 的 FullAjaxExceptionHandler:

<factory>
    <exception-handler-factory>
        org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory
    </exception-handler-factory>
</factory>

FullAjaxExceptionHandler 对于 ajax 调用工作正常,但是当我直接点击一个页面并且出现错误时,它会开始呈现我试图访问的页面,但它没有完成,然后是 web.xml 中定义的错误页面。 xml 被渲染,这导致错误页面在部分渲染页面之后被嵌入。

(我正在使用具有 Mojarra JSF 2.1.3 的 Glassfish 3.1.1)编辑:现在使用 Glassfish 3.1.2.2 和 JSF 2.1.11

编辑:发现以下内容:发生错误的页面正在使用模板(<ui:composition template="/shared/shared/commonLayout.xhtml">)如果我更改它以使页面不再使用模板,然后只需添加模板中的所有代码,它就可以正常工作。

4

1 回答 1

5

当在抛出异常之前响应已经提交时,就会发生这种情况。当以某种方式显式调用 JSF 覆盖的深处时,将提交响应ServletOutputStream#flush(),这通常仅在响应缓冲区(在大多数容器中通常默认为 2KB)已溢出时才提交。承诺的响应是不归路的。服务器无法从客户端取回已经发送的字节。服务器基本上有2个选项:

  • 保留响应并仅将异常记录到服务器日志中。
  • 无论如何尝试将错误页面写入响应。

您的 Glassfish 设置显然选择了第二种方式。它们都不是完美的。客户端仍然会得到一个半生不熟的 HTML 响应,最终用户看起来会是什么样子取决于网络浏览器如何在解释和呈现迄今为止获得的 HTML 方面做到最好。

但是,作为 JSF 开发人员,您可以使用多种方法来避免这种情况发生。首先,为什么在呈现响应期间会抛出异常?这实际上不是表明您自己的代码中存在错误吗?在呈现响应之前,您不是更好地执行对异常敏感的业务工作吗?您可以<f:event type="preRenderView">为此使用。

<f:event type="preRenderView" listener="#{bean.init}" />

如果由于某种原因这确实不是一个选项,您可以考虑将响应缓冲区大小增加到最大 HTML 响应的大小以上,以便在发生异常之前不会自动刷新响应。您可以通过以下上下文参数来做到这一点,该参数假定每个 HTML 响应都符合 100KB 的限制:

<context-param>
    <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
    <param-value>102400</param-value><!-- 100KB -->
</context-param>
于 2012-08-02T19:36:03.543 回答