2012-08-01 105 views
5

我有以下web.xml中定義:錯誤頁面被嵌入在部分地呈現JSF頁

<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> 

我還使用了從FullAjaxExceptionHandler Omnifaces faces-config.xml中:

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

的FullAjaxExceptionHandler工作正常進行Ajax調用,但是當我直接打一個網頁,並有一個錯誤,它開始渲染我試圖去的網頁,但它並沒有完成,然後在web.xml中定義的錯誤頁面被渲染,這導致錯誤頁面被嵌入d在部分呈現的頁面之後。

(我使用Glassfish的3.1.1具有鑽嘴魚科JSF 2.1.3)編輯:現在使用的Glassfish 3.1.2.2和JSF 2.1.11

編輯:發現了以下內容: 所在的頁面錯誤正在發生的是使用模板(<ui:composition template="/shared/shared/commonLayout.xhtml">)如果我改變它,使頁面不再使用模板,然後只需添加模板中的所有代碼,然後它可以正常工作。

+0

這很奇怪。爲了排除這個和那個,JSF項目階段是否設置爲'Development'? – BalusC 2012-08-02 02:34:28

+0

是的,它被設置爲開發。 – jc12 2012-08-02 15:03:01

+0

我試着將它改爲Production,但我仍然得到相同的結果。我不確定你的意思是「排除一個和其他」。如果我使用FullAjaxExceptionHandlerFactory進行ajax調用,是否還需要一個用於非Ajax調用的ExceptionHandlerFactory? – jc12 2012-08-02 15:21:16

回答

5

如果在拋出異常之前已經提交了響應,則會發生這種情況。當ServletOutputStream#flush()已經深入JSF中時,響應將會以某種方式被明確調用,而這通常僅在響應緩衝區(通常在大多數容器中默認爲2KB)溢出時纔會被提交。承諾的迴應是一個不歸路。服務器無法從客戶端取回已發送的字節。服務器基本上有2個選項:

  • 保留響應原樣並僅將例外記錄到服務器日誌。
  • 嘗試將錯誤頁面寫入響應。

Your 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> 
+0

增加緩衝區大小的工作,謝謝!在ManagedBean中的PostConstruct期間發生錯誤。在頁面上使用了許多託管的bean,並且大多數託管bean在具有PostConstruct註釋的方法中都有自己的設置代碼。爲了使用preRenderView,我必須把所有的init代碼放到一個單獨的函數中,或者你可以有多個preRenderView事件,但是你必須維護每個頁面的事件。 – jc12 2012-08-02 20:01:56