Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

jsf 2 - Error page defined in web.xml is embedded in partially rendered JSF page

I have the following defined in 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>

I'm also using the FullAjaxExceptionHandler from Omnifaces in faces-config.xml:

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

The FullAjaxExceptionHandler is working fine for ajax calls, but when I hit a page directly and there is an error, it starts rendering the page I was trying to go to, but it doesn't finish, and then the error page defined in web.xml is rendered, which results in the error page being embedded after a partially rendered page.

(I'm using Glassfish 3.1.1 which has Mojarra JSF 2.1.3) Edit: now using Glassfish 3.1.2.2 and JSF 2.1.11

Edit: Discovered the following: The page where the error is happening is using templates (<ui:composition template="/shared/shared/commonLayout.xhtml">) If I change it so that the page is no longer using the template, and then just add in all of the code from the template then it works fine.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This will happen when the response is already committed before the exception is been thrown. The response will be committed when ServletOutputStream#flush() has deep under the JSF covers explicitly been invoked in some way, which is more than often only when the response buffer (defaults usually to 2KB in most containers) has been overflowed. A committed response is a point of no return. The server cannot take the already-sent bytes back from the client. The server has basically 2 options:

  • Leave the response as is and log the exception to the server log only.
  • Try writing the error page to the response anyway.

Your Glassfish setup apparently chooses the 2nd way. None of them is perfect. The client would still end up with a halfbaked HTML response and whatever it would end up to look like to the enduser depends on how the webbrowser can do its best in interpreting and presenting the so far obtained HTML.

You, as JSF developer, can however use several approaches to avoid this from happening. In first place, why exactly is that exception been thrown during rendering the response? Doesn't that actually indicate a bug in your own code? Wouldn't you better perform the exception-sensitive business job before rendering the response? You could use among others <f:event type="preRenderView"> for this.

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

If that's really not an option for some reason, you could consider increasing the response buffer size to above the size of the largest HTML response, so that the response won't be auto-flushed before the exception occurs. You can do that by the following context parameter which assumes that every HTML response fits within the 100KB limit:

<context-param>
    <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
    <param-value>102400</param-value><!-- 100KB -->
</context-param>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...