簡介
HTTP協議是無狀態的。從客戶端到服務器的連接可以在每個請求之后關閉。但是一般需要把一些客戶端信息從一個頁面傳送給另一個頁面。
- 無狀態的根本原因是:瀏覽器和服務器使用Socket通信,服務器將請求結果返回給瀏覽器后,會關閉當前Socket連接。而且服務器會在處理頁面完畢后銷毀頁面對象。
- 應用層面的原因是:瀏覽器和服務器之間通信都遵守HTTP協議。
- Http協議是無狀態的,不會記得上次和網頁“發生了什么。服務器不記得上次給了瀏覽器什么。
- 對網站造成的影響:如果用戶錄入了一些信息,當跳轉到下一個頁面時,數據丟失,再也不能獲得那些數據。
如果要知道上一次的狀態信息,我們就得把這個狀態信息記錄在某個地方:
a.服務器端
b.瀏覽器端(客戶端)
c. 表單元素中—如:隱藏域<input type=“hidden”/>(Http報文)
在保存狀態的各種方式中,主要區別是:狀態是存儲在客戶端還是服務器上,下表列出了各種狀態管理技術以及狀態保持有效的時間。
狀態類型 | 客戶端或服務器資源 | 有效時間 |
ViewState | 客戶端 | 只在一個頁面中 |
Cookie | 客戶端 | 關閉瀏覽器時會刪除臨時cookie(此時的cookie沒有設置有效時間,存儲在瀏覽器內存中,關閉瀏覽器cookie自動刪除),永久存儲在用戶系統磁盤上。 |
Session | 服務器 | 回話狀態與瀏覽器回話相關。回話在超時后無效(默認為20分鍾) |
Application | 服務器 | 應用程序狀態在所有的客戶端上共享,這個狀態在服務器重啟之前都是有效的 |
Cache | 服務器 | 類似於應用程序狀態,高速緩存是共享的。但是,使高速緩存無效有更好的控制方式 |
先將狀態管理的五種方式基本概念放在一起,方便比較記憶。
網絡上有一種划分更細的方案,如下圖所示:
客戶端的狀態保持方案:ViewState、隱藏域、Cookies、控件狀態、URL查詢參數
服務端的狀態保持方案:Session(會話)、Application、Caching(緩存)、DataBase(數據庫)
客戶端的狀態管理
- ViewState
關於ViewState講的太多了,我這里也是將需注意的地方寫下來,方便日后查詢,當然也希望能幫到別人。Web服務器控件自動使用ViewState來使事件工作。ViewState包含的狀態與控件發送給客戶端時所包含的狀態相同。當瀏覽器把窗體發送給服務器時,ViewState包含了初始值,但所發送的控件包含新值。如果初始值和新值有區別,就調用相應的時間處理程序。
使用ViewState的缺點是。數據總是要從服務器傳送給客戶端,再從客戶端傳送給服務器,增加了網絡流量。為了減少網絡流量,可以關閉ViewState。在Page指令中把EnableViewState屬性設置為false,就可以關閉頁面中所有控件的ViewState。
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Wolfy.WebChat.Server.Default" EnableViewState=" false" %>
設置一個控件的EnableViewState屬性,也可以配置該控件的ViewState。無論頁面進行了什么配置,只要定義了控件的EnableViewState屬性,就使用控件配置的值(優先級較高),只有沒有配置ViewState的控件才使用頁面配置的值。
還可以把定制的數據存儲在ViewState中。為此可以使用索引符和page類的ViewState屬性。可以設置Index參數定義一個名稱,用於訪問ViewState值。
ViewState["mydata"] = "中秋節快樂";
可以讀取前面存儲的ViewState,如下所示:
string mydata = (string)ViewState["mydata"];
在發送給客戶端的HTML代碼中,整個頁面的ViewState存儲在一個隱藏域中:
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="pRdkV9UzTFimveKGNXH7EJyJbDjTrumX55ovGtz5zcgHVPI4HrWrE+I81Ox6/Pb8mOi2UVpNLkMyuEpl5Zj6UQQwwJpxpHbUpZbe2TkcyAJnmLda+oPgf/vO+rmInjm1" />
使用隱藏域的優點是,每個瀏覽器都可以使用這個特性,用戶不能關閉它。
ViewState只保存在頁面中。如果狀態應保存在多個不同的頁面中,就應使用cookie在客戶端保存狀態。
總結:
默認情況下,ViewState是被啟用的,比如提交表單后,表單中輸入的值會自動保留。但是如果不需要保留,也可以將其禁用,這樣可以節省資源。
-
- 服務器在接收到用戶請求一個頁面后,會自動在請求報文中找看是否包含__VIEWSTATE的隱藏域,如果有,則將中間的值解碼后添加到頁面的ViewState屬性中。
- 服務器在輸出的時候,也會自動的將ViewState中的值添加到表單里名叫__VIEWSTATE的隱藏域中
-
- VIEWSTATE適用於同一個頁面在不關閉的情況下多次與服務器交互
下面3種方式就可以分別禁用某一個控件、某一個頁面和整個應用程序的ViewState。
1) 控件禁用:將控件的EnableViewState屬性設置為false;
2) 頁面禁用:在頁面的Page指令中添加EnableViewState="false";
3) 應用程序禁用:在Web.Config文件中添加
<configuration> <system.web> <pages enableViewState="false"></pages> </system.web> </configuration>
2. Cookie
cookie在HTTP頭中定義。使用HttpResponse類可以把cookie發送給客戶端。Response是Page類的一個屬性,它返回一個HttpResponse類型的對象。HttpResponse類定義了返回HttpCookieColletion的Cookies屬性。使用HttpCookieColletion可以向客戶端返回多個cookie。
下面的實例代碼說明了如何把cookie發送給客戶端。首先,實例化一個HttpCookie對象。在這個類的構造函數中,設置cookie的名稱,這里是mycookie。HttpCookie類的Values屬性可以添加多個cookie值。如果只返回一個cookie的值,就可以使用Value屬性。但如果要發送多個cookie值,最好把值添加到一個cookie中,而不是使用多個cookie。
1 string myval = "myval"; 2 HttpCookie cookie = new HttpCookie("mycookie"); 3 cookie.Values.Add("mystate", myval); 4 Response.Cookies.Add(cookie);
cookie可以是臨時的,僅在一個瀏覽器回話中有效,也可以存儲在客戶端的磁盤上。為了使cookie變成永久的,必須使用HttpCookie對象設置Expires屬性。使用Expires屬性可以定義cookie不再有效的日期,這里把它設置為三個月后。
盡管可以設置特定的日期,但不能保證cookie會存儲到該日期位置。用戶可以刪除cookie,如果在本地存儲了太多的cookie,瀏覽器應用程序也可能刪除它,瀏覽器只能為每個服務器存儲20個cookie,為所有的服務器存儲300個cookie(根據各瀏覽器而定)。達到極限后,就刪除有一段時間已不再使用的cookie。
1 string myval = "myval"; 2 HttpCookie cookie = new HttpCookie("mycookie"); 3 cookie.Values.Add("mystate", myval); 4 cookie.Expires = DateTime.Now.AddMonths(3); 5 Response.Cookies.Add(cookie);
客戶端從服務器上請求一個頁面時,這個服務器的cookie就可以在客戶端上使用,並作為http請求的一部分發送給服務器。要在Asp.Net頁面中讀取cookie,可以訪問HttpRequest對象中的cookie集合。
與Http響應一樣,Page類也有一個Request屬性返回HttpRequest類型的對象。Cookies屬性返回HttpCookieCollection,它可以用於讀取客戶端發送的cookie。可以用索引符通過其名來訪問cookies,然后使用HttpCookie的Values屬性從cookie中獲取值。
1 HttpCookie cookie = Request.Cookies["mycookie"]; 2 string myval = cookie.Values["mystate"];
Asp.Net很容易使用cookie。但必須了解cookie的限制。如前所述,瀏覽器只能接收來自一個服務器的20個cookie,以及來自所有服務器的300個cookie。另外,cookie的大小也有限制。cookie不能存儲多余4K的數據。這些限制的存在使客戶端磁盤不會被cookie占滿。
Cookie原理:cookie是如何往返的?
* 服務器向瀏覽器寫出Cookie實際上就是在 響應報文中 生成響應行:
* Set-Cookie: uinfo2=123; expires=Mon, 06-Jun-2011 06:48:47 GMT; path=/
* 瀏覽器讀取此 響應行后 會自動在客戶端硬盤中產生一個Cookie文件,名為:
* Cookie:administrator@localhost/,注意@后的 localhoust/ ,實際上是頒發此Cookie網站的域名;
* 當瀏覽器下次再訪問此域名時,就會自動將 后綴為 localhoust/ 的cookie文件內容發送到服務器。
補充:
不同瀏覽器間cookie總大小也不同:
Firefox和Safari允許cookie多達4097個字節,包括名(name)、值(value)和等號。
Opera允許cookie多達4096個字節,包括:名(name)、值(value)和等號。
InternetExplorer允許cookie多達4095個字節,包括:名(name)、值(value)和等號。
瀏覽器允許每個域名所包含的cookie數:
Microsoft指出InternetExplorer8增加cookie限制為每個域名50個,但IE7似乎也允許每個域名50個cookie。
Firefox每個域名cookie限制為50個。
Opera每個域名cookie限制為30個。
Safari/WebKit貌似沒有cookie限制。但是如果cookie很多,則會使header大小超過服務器的處理的限制,會導致錯誤發生。
注:“每個域名cookie限制為20個”將不再正確!
當很多的cookie被設置,瀏覽器如何去響應。
除Safari(可以設置全部cookie,不管數量多少),有兩個方法:
最少最近使用(leastrecentlyused(LRU))的方法:當Cookie已達到限額,自動踢除最老的Cookie,以使給最新的Cookie一些空間。InternetExplorer和Opera使用此方法。
Firefox很獨特:雖然最后的設置的Cookie始終保留,但似乎隨機決定哪些cookie被保留。似乎沒有任何計划(建議:在Firefox中不要超過Cookie限制)。