1. 程式人生 > >不同瀏覽器Session使用和常見問題分析

不同瀏覽器Session使用和常見問題分析

 session跟蹤機制

HTTP協議為無狀態協議,對於每一個web請求,伺服器是無法知道是否為同一個請求者。那麼是怎麼樣跟蹤請求的呢?


目前有兩種方式。

第一種,使用cookie記錄標誌。瀏覽器是可以儲存cookie資訊的,在請求響應的時候,建立一個對應的cookie,記錄一個編號,下次再發送請求的時候,將cookie記錄的資訊傳送到伺服器上,伺服器取得這個值,就可以判斷是否為同一個使用者傳送的請求了。


 第二種,使用URL重寫。每次URL後面跟隨一個引數,伺服器取得這個引數,也可以判斷是否為同一個使用者的請求。

index.html; jsessionid=1234

對應用伺服器來說,會先檢查瀏覽器是否支援cookie,如果支援就採用cookie,如果不支援則自動採用URL重寫,這個過程是由Servlet規範規定的,所有的Servlet容器都需要實現這樣的功能,不需要人為干預。

session超時機制

當然,如果伺服器一直儲存session資訊,使用者關閉了瀏覽器,或者離開了網站,session資訊就沒有必要儲存在伺服器上了。怎麼清理呢?

Session的超時機制就是來處理這種情況的,如果在規定的時間內,第一次請求時,伺服器建立新的session,並且會記錄時間,如果很長時間沒有資訊相同的session id資訊過來,伺服器會人為使用者沒有使用了,就自動清理掉這個對應的這個session了。

參考web.xml的配置sessiontimeout項。

JSP作用域

1、page

這個作用域是最嚴格的,此物件只對於它所在JSP頁面是可訪問的。

2、request

這個作用域的物件是在相應請求的生命週期內有效。也就是說,物件在建立它的頁面內有效,以及請求被轉發(forward方法)或者被包含(include方法)的頁面內有效。

3、session

會話域的物件,對於參與某個客戶端會話週期的所有請求,資料都是一致的。如果有多個請求操作session,可能會有多執行緒的問題。

比如先發送A請求,立即傳送B請求:

A請求訪問session,設定某一個屬性的值為a。

B請求讀取session,讀取A設定的屬性值。

如果在A響應之前B請求已經發出去了,B讀取的時候A還沒有設定,B讀取到的值就不是a了。

4、application

這是最寬泛的作用域,application裡的變數可以被所有使用者共享,類似全域性變數。這類物件不是執行緒安全的,如果多個請求試圖同時修改某一個物件,那麼必須對這些訪問進行同步處理。  

如果使用者甲的操作修改了application中的變數,使用者乙訪問時得到的是修改後的值。這在其他 scope中都是不會發生的,page, request, session都是完全隔離的,無論如何修改都不會影響其他人的資料。

HttpSession介面

Servlet API只是定義了一組介面和一些實現類,HttpSession就是一個介面,具體的實現類不同的servlet容器有不同的實現。

比如weblogic8裡面使用的是HashTable來儲存session的屬性和值,而tomcat6裡面則是使用ConcurrentHashMap來儲存。

HttpSession常用方法:

getAttribute(java.lang.String name)
返回session中繫結的變數名的值,如果沒有則返回null
getId()
返回jsessionId的值
invalidate()
取消當前會話,系統退出之前呼叫
removeAttribute(java.lang.String name)
刪掉session某繫結的變數
setAttribute(java.lang.String name, java.lang.Object value)
新增對於的名稱和值到session中

什麼情況下使用session

1.  儲存使用者特定資料,比如使用者角色,操作集合等

2.  多個不同請求之間的共享資料

什麼情況下不能使用session

1.  對所有使用者都可以共享的資料,比如機構列表快取,系統某功能的配置基表等

2.  資料提交前的臨時存放,可能存在資料覆蓋的情況,使用request轉發或使用隱藏表單

針對同一域中的操作的比較

新視窗開啟方式

IE6

IE8

CTRL+N

共享session

共享session

winodw.open

共享session

共享session

連結

共享session

共享session

開啟IE

新建session

共享session

建立標籤頁

共享session

對於同一使用者從同一系統中同時開啟多個相同的頁面,此時瀏覽器會共享session,如果這個頁面操作,伺服器上有更新session物件的資訊,可能會導致session資訊會被覆蓋。

 

舉例:

       開啟頁面page.jsp後,輸入資訊,然後提交,提交時從session取key的值。

       假設某頁面page.jsp每次開啟之後,都會根據資料設定session。

    第一次的資料值為value1:

    session.setAttribute("key","value1");

    第二次的資料值為value2:

    session.setAttribute("key","value2");

     同時開啟兩個page.jsp,第一次開啟之後未提交,第二次開啟之後也未提交。

    此時,如果回到第一個頁面,並提交,取到的key值是value2,資料有異常。

    回到第二個頁面,並提交,取到的key值是value2,資料正常。

規避措施:

a. 禁止同一頁面同時開啟多次

b. a條件不滿足的情況下,不使用session儲存資料,考慮使用頁面表單的hidden域傳值,或者使用request請求轉發

c. 對於GET請求,可以使用URL重寫,加入引數,敏感資訊需要加密不能使用

如果需要儲存臨時資料,該怎麼辦

有時候為了增加客戶體驗,需要在後面的頁面中保留上一個頁面輸入的內容,例如分頁顯示列表,這個時候有兩種做法可以選擇。

A. 使用頁面表單隱藏資料。將計算得到總條數,總頁數,每頁的數量,當前頁數,開始的索引等資料放到頁面表單中,當選擇下一頁或者上一頁時,每次都將這些資料傳到後臺進行處理。

 B. 使用session快取。將計算得到總條數,總頁數,每頁的數量,當前頁數,開始的索引等資料組裝成分頁物件放到session中,當選擇下一頁或者上一頁時,後臺從session中獲取資料,再進行處理。 

對於同一客戶不同產品進行的受理,存在session資料覆蓋的情況,此時就要特別注意了。如果改造成頁面隱藏欄位的方式確實很困難,在使用session的時候,可以對不同的產品進行拆分,使用跟產品相關的session key值,比如,可以使用保單號作為session的key,而不是使用保單物件。

程式碼示例:

PolicyDTO policy=new  PolicyDTO ();
session.setAttribute(“policyDTO”,policy);//會產生資料覆蓋問題
session.setAttribute(policyDTO.getPolicyNo,policy);//不會產生資料覆蓋問題

在服務退出或者受理提交之後,需要清理掉session中的資料,否則會造成垃圾資料過多,伺服器記憶體洩露。

在IE6中,不同方式會有不同的行為,在IE8中,不同視窗共享一個會話。如果要使IE8和IE6在開啟IE時,表現一致,在IE8啟動引數中加入-nomerge。

對於多個不同請求之間共享的資料,如果放在session中,可能存在併發的問題。

請求響應的時間,由於網路,伺服器等因素可能慢,也可能快,如果先後傳送兩個請求到伺服器,可能後傳送的請求會先響應,這時取到的值就不是期望的了。

示意圖如下,和圖三是有區別的,2A表示先於寫之前取值,2B表示正常的情況。

 

對於這樣的情況,可以使用順序操作,設定session之後,跳轉到一個新的頁面,在新的頁面上在去讀session裡面的資料。見示意圖五。

模態視窗session丟失問題

在IE中使用showModalDialog方法開啟一個新的視窗的時候,會建立一個新的視窗例項。如果這個例項是在新的程序中開啟的,所有的cookies和session id都不能使用了,這個例項和winodw.open方法開啟的例項是不一樣的,也就是說showModalDialog在新程序中開啟的視窗,和父視窗不共享session,這裡使用的時候需要特別注意。

關於showModalDialog方法的詳細描述,請參考連結文件:

在msdn上搜索 showModalDialog method
此處無法提供連結