2011-08-12 71 views
2

我有一個在IE,FF,Safari和Chrome上運行良好的glassfish 3.1上運行的JSF 2.0 web應用程序。當在Safari中使用iframe時,GlassFish 3.1上的JSF 2.0 ViewExpiredException

當我在另一個網站的iframe中添加我的網站的網址時,我點擊iframe內的任何按鈕後,我得到ViewExpiredException - 這隻發生在Safari上,在IE,FF,Chrome中正常工作。

<iframe style="width: 100%; height: 800px" src="url_of_my_website" frameBorder="0"></iframe> 

以下是我的觀察

  1. 部署在GlassFish 3.0.1相同的應用程序和問題不會發生
  2. 如果我打開我的網站沒有框架,它不考慮工作的瀏覽器罰款
  3. 開發利用JSF1.2和RF 3.3.3相同的應用程序和問題不會發生

根據我的理解,如果在會話過期的頁面上執行任何操作,我們將得到ViewExpiredException。但在這種特殊情況下,它恰好在網站獲得負載之後發生。

我不確定是什麼原因造成的。它是Safari/JSF 2.0/GF 3.1/IFRAME嗎?

更新: 我發現了一個有趣的問題。在我的主頁上,我有一個h:commandLink將我重定向到一個新頁面。此外,我有一個href鏈接重定向到其他頁面。當我點擊commandLink時,我得到了ViewExpiredException,但是當我點擊href鏈接時,我沒有收到任何異常,並且頁面被重定向,並且隨着會話cookie的建立,我可以繼續進一步的操作。

+0

根據您的更新:這是正常的。命令鏈接提交一個隱藏的表單並有效地觸發一個POST請求,因此要求在同一個會話中觸發請求。普通鏈接激發GET請求,該請求不需要在同一個會話中觸發請求。只需要一個新的會話即可創建。如果您不需要提交額外的POST數據,則根本不需要命令鏈接。 – BalusC

回答

3

這確實是一個known problem。 Safari不允許跨域Cookie。這個瀏覽器會忽略任何由iframe提供的cookie。 HTTP會話由一個cookie支持。所以它也不會保持。因此,當您在iframe中提交JSF表單時,Safari將不會將會話cookie發回,並且服務器端將隱式創建新會話,因此在初始會話中設置的視圖完全丟失。因此ViewExpiredException

理論上,可以通過解決此問題,將JSESSIONID片段包含在JSF生成的HTML <form>元素的action URL中。例如。

<form action="/context/page.xhtml;JSESSIONID=1234567890ABCDEF"> 

但是,JSF已經這樣做了。它爲此使用了HttpServletResponse#encodeURL()。這對於JSF 2來說並不適用,而它顯然在JSF 1.2上工作對我來說是一個謎。但是你現在至少應該集中注意力。 HttpServletResponse#encodeURL()是否在JSESSIONID之內返回了正確編碼的URL?生成的HTML <form>是否包含JSESSIONID?等等。當使用Mojarra時,在調試時從FormRenderer#getActionStr()方法開始。

無論如何,另一個解決方案是使用JavaScript來做到這一點。在載入要在iframe中顯示的JSF頁面時,請執行以下操作。以下腳本啓動示例應嵌入在JSF頁面中,以便對#{}進行評估。

window.onload = function() { 
    if (top != self) { // If true, then page is been requested inside an iframe. 
     var jsessionid = '#{session.id}'; 
     var forms = document.forms; 

     for (var i = 0; i < forms.length; i++) { 
      forms[i].action += ';JSESSIONID=' + jsessionid; 
     } 
    } 
} 

應該不會損害非Safari等瀏覽器。

+0

感謝您的回覆。我嘗試了JavaScript,但它不適合我。我的所有網頁都使用模板,所以我在那裏添加了javascript。僅供參考,在我的過濾器的doFilter()方法中,我正在檢查HttpServletRequest#isRequestSessionIdFromURL(),如果它是真的,那麼我將用戶重定向到主頁。如果解決方法的javascript工作,這會是一個問題嗎? – Praneeth

0

我遇到了IE和Safari的相同問題。 這是因爲這些瀏覽器默認情況下不允許第三方Cookie。 因此會話ID無法通過cookie傳遞。

要修復它在IE足以增加響應頭P3P與價值CP =「此網站沒有P3P策略」:

ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext(); 
extContext.addResponseHeader("P3P", "CP=\"This site does not have a p3p policy.\""); 

要修復它在Safari足以傳送會話ID在url中,但不是在cookie中。這被稱爲URL重寫。對於支持Servlet 3.0的應用服務器,可以使用web.xml完成​​:

<session-config> 
    <tracking-mode>URL</tracking-mode> 
</session-config>