對企業級應用開發的思考(2)--會話狀態

    在我們使用HTTP協議進行應用開發的的時候,通常服務器端是不關心請求是從哪個客戶到來的,客戶端也不併不關心服務器端是通過生成哪個對象處理的這次請求。這就是我們通常說的HTTP無狀態請求,從技術的角度上講是因爲:

  • 客戶端和服務器用TCP Socket通信,服務器將請求結果返回給瀏覽器後,通常會關閉Socket連接;
  • 服務器會在處理頁面完畢後銷燬頁面對象;
  • HTTP協議本身就是一個無狀態協議;

    舉個例子,如返回一個Web頁面告訴你關於一個商品的信息。可以通過訪問一個URL請求服務器。在URL中帶有該商品的ID號,服務器用它來產生HTTP頁面進行響應。在這個過程中,服務器生成HTML頁前可能記住了這個商品的ID以及從數據庫取出來的商品名稱/價格等信息,並可以通過業務邏輯來決定按哪種風格來顯示給客戶。一旦服務器完成工作,那些信息就沒有任何作用了。

    然而我們的業務邏輯通常要求服務端與客戶端交互是有狀態的。最常見的是很多業務系統要登陸後才能進行操作,而且在整個操作過程中都要攜帶登陸信息,登陸信息便是會話狀態;再比如網購過程中的購物車功能,購物車的內容就是會話狀態。這些都是比較典型的基於狀態的交互。基於會話的交互關鍵是如何存儲會話狀態信息,因爲通信的兩方只有客戶端和服務端,所以會話狀態的存儲方式也有兩種:存儲在服務器端和存儲在客戶端。

客戶端存儲

    客戶端存儲能常有這樣幾種方法:數據編碼在URL中、WEB表單的隱藏域中、HTML擴展標籤及cookie。這裏簡單說一下具體的操作:

  • URL方法:這種方法最常見的就是在分頁的時候,URL中帶放有頁碼信息。比如:xx.aspx?page=3 這種方式是最簡單有效的方法。但缺點也很明顯,安全係數基本爲0,而且只適合存儲小數據量。
  • WEB表單隱藏域: 這種方式和把信息存儲在HTML擴展標籤中,還有可能在胖客戶端的對象結構中其實是差不多一樣的。最明顯的一個例子就是asp.net中爲表單自動生成的那一堆viewdata,它們的原理都是在客戶端的WEB頁面中放置一些普通用戶看不見的東西。所以可以把它們歸爲一類,至於實際項目中選擇使用哪種方式,全憑開發者個人愛好及客戶瀏覽器的支持情況。它的一個典型的實現如下:
1 <input type="hidden" value="你的會話狀態信息" id="sessionData"/>

 

  • Cookie:這是一種非常流行的做法。個人認爲它流行的原因,很大一部分是因爲程序編碼者可以直接通過服務端代碼實現,而不用像上面那種方式,還要去處理HTML。比如可以直接使用C#實現:
/// <summary>
/// 寫cookie值
/// </summary>
/// <param name="strName">名稱</param>
/// <param name="strValue"></param>
/// <param name="strValue">過期時間(分鐘)</param>
public static void WriteCookie(string strName, string strValue, int expires)
{
    HttpCookie cookie = HttpContext.Current.Request.Cookies[strName];
    if (cookie == null)
    {
        cookie = new HttpCookie(strName);
    }
    cookie.Value = strValue;
    cookie.Expires = DateTime.Now.AddMinutes(expires);
    HttpContext.Current.Response.AppendCookie(cookie);

}

/// <summary>
/// 讀cookie值
/// </summary>
/// <param name="strName">名稱</param>
/// <returns>cookie值</returns>
public static string GetCookie(string strName)
{
    if (HttpContext.Current.Request.Cookies[strName] != null)
    {
        return HttpContext.Current.Request.Cookies[strName].Value.ToString();
    }
    return "";
}

 

     通過簡單的服務端語言就可以實現cookie的讀寫,而且不需要處理任何數據傳遞/接收的處理。這樣方便是方便,但以前面試過一些人,當問到爲什麼可以用服務器代碼讀寫存在於客戶端電腦上面的cookie時,令我喫驚的是,很多人就只敷衍一句,asp.net的內部機制,我們不用關心。我只想說這些人純粹就是爲了寫代碼而寫代碼,完全沒有思考過其中的原因。

cookie

上圖是cookie的標準流程圖,在HTTP協議中有一些與cookie有關的擴展頭部。幫助我們自動實現cookie信息在客戶端與服務端傳輸。如下:

cookie2

    當在服務端寫一個Cookie時,服務器在回傳的HTTP中,會添加Set-Cookie把剛剛寫入的內容傳遞到客戶計算機中。當客戶端再次請求該服務器時,會在請求的HTTP頭中添加cookie信息,傳遞到服務器中,這樣才能使服務器代碼正常訪問到。

服務器存儲

    在服務器端存儲會話信息通常有兩個選擇:直接存儲在內存中序列化存儲在文件系統中(當然,包括存儲到數據庫中)。對於面向對象的開發語言來說,通常使用靜態數據對象(或集合)把狀態存儲在內存中,這樣只想應用程序或服務器不重啓,那麼狀態就可以一直存在,內存狀態的典型代表就是asp.net內置的會話狀態功能--Session。如果想把狀態存儲在文件或數據庫中,最好的方法就是把會話標識作爲關鍵字,以已序列化的對象爲值進行存儲。比如我們可以以SessionId作爲關鍵字,把Session的內容序列化並存儲到數據庫中,這樣就可以避免重啓造成的Session丟失問題。關於Session的使用可以查看《認識asp.net會話狀態》,本文不再詳述。

    服務端存儲並沒有什麼特殊要講的地方,因爲即不用考慮怎麼把內容藏在客戶電腦裏面,並且讓他們不易發現,也不用考慮太多安全問題。

 

抉擇

    瞭解完兩邊的存儲情況後,伴隨而來的一個問題就是:我到底該把狀態存在哪裏?

    下表總結了一下,兩種存儲方式的優點及適用場景:

  優點 適用場景
服務端存儲 數據安全性高;
簡單,主流服務端開發的支持,大幅減少代碼量;
本人是服務端會話存儲的支持者,除下面列舉的兩種情況外,我基本都會把會話狀態存儲在服務器。
客戶端存儲 用戶客戶端存儲,減少服務器壓力; 1、適合會話狀態數據量較少的情況;特別適合存放會話標識,典型的就是Session ID。
2、適合一些臨時會話狀態,比如購物車。因爲用戶可能經常取消該會話,並且再也不會用到它。

    兩種模式在實際應用中並不是相互排斥的關係,且不存在絕對的誰好誰壞,可以靈活組合使用。但這樣會增加程序編碼的複雜度,開發者可以根據自己的情況選擇使用。

 

    附:本博客其他精彩內容:http://www.cnblogs.com/yubaolee/p/Catalogue.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章