一、寫(xiě)在前面 我們?cè)谑褂肁SP.NET開(kāi)發(fā)的過(guò)程中,有時(shí)會(huì)進(jìn)行數(shù)據(jù)存儲(chǔ)以實(shí)現(xiàn)請(qǐng)求前后的狀態(tài)保持(HTTP是無(wú)狀態(tài)保持的協(xié)議),而Session作為一種快速簡(jiǎn)單易于實(shí)現(xiàn)的方式被我們經(jīng)常使用,當(dāng)然如果出于性能方面的考量,我們還是不建議往Seesion中塞入更多的東西,最好是不用Session。 還有一點(diǎn)需要說(shuō)明的是,Session實(shí)現(xiàn)的本質(zhì)是在客戶端產(chǎn)生一個(gè)SessionId,具體的數(shù)據(jù)存儲(chǔ)在服務(wù)器端,客戶端通過(guò)SessionId來(lái)獲取服務(wù)器端的具體數(shù)據(jù),那這個(gè)SeesionId是怎么保存在客戶端以及又是以什么方式來(lái)傳給服務(wù)器的呢?服務(wù)器端又是以什么方式保存Session的這些數(shù)據(jù)的呢?各種方式的優(yōu)缺點(diǎn)又是什么?這就是本篇隨筆想要記錄的內(nèi)容。 二、配置方式 <sessionState mode='Off|InProc|StateServer|SQLServer' cookieless='true|false' timeout='number of minutes' stateConnectionString='tcpip=server:port' sqlConnectionString='sql connection string' stateNetworkTimeout='number of seconds' /> 上面是Session在Web.config的配置方式,下面對(duì)各個(gè)節(jié)點(diǎn)做一些簡(jiǎn)單的介紹 mode(設(shè)置將服務(wù)器的Session信息存儲(chǔ)到哪里) Off表示設(shè)置為不使用Session功能; InProc表示將Session存儲(chǔ)在進(jìn)程內(nèi),這也是ASP中的存儲(chǔ)方式,這是默認(rèn)值; StateServer表示將Session存儲(chǔ)在獨(dú)立的狀態(tài)服務(wù)即ASP.NET State Service中; SQLServer表示將Session存儲(chǔ)在SQL Server。 cookieless(設(shè)置客戶端的Session信息存儲(chǔ)到哪里) true表示使用Cookieless模式(這表明SessionId將不再使用Cookie存儲(chǔ)了,而是將其通過(guò)URL存儲(chǔ)); false表示使用Cookie模式,這是默認(rèn)值。 從上面的設(shè)置配置中我們也可以發(fā)現(xiàn)Session和Cookie的關(guān)系: 首先Session在客戶端的實(shí)現(xiàn)肯定是SessionId; 默認(rèn)這個(gè)SessionId是通過(guò)Cookie存儲(chǔ)的(比較安全); 當(dāng)然也可以通過(guò)URL來(lái)進(jìn)行存儲(chǔ),這樣Session和Cookie就沒(méi)有關(guān)系了,但是此種方式由于受URL長(zhǎng)度限制以及明文傳送導(dǎo)致不安全而不被推薦使用。 Session過(guò)期時(shí)間設(shè)置,默認(rèn)為20分鐘。 stateConnectionString 如果設(shè)置將Session信息存儲(chǔ)在State Server中時(shí),則需要此配置字符串表明服務(wù)器名稱和端口。 sqlConnectionString 如果設(shè)置將Session信息存儲(chǔ)在SQL Server中,需此配置,表明數(shù)據(jù)庫(kù)的連接字符串,同時(shí)stateNetworkTimeout表明經(jīng)過(guò)多少秒空閑后,斷開(kāi)Web服務(wù)器與存儲(chǔ)狀態(tài)信息的服務(wù)器的TCP/IP連接的。默認(rèn)值是10秒鐘。 三、Session服務(wù)器端配置 1. InProc顧名思義,此種模式表示Session將會(huì)被保存在內(nèi)存中,確切地說(shuō)是保存在工作者進(jìn)程中,對(duì)于IIS 5而言是aspnet_wp.exe,對(duì)于IIS 6而言是w3wp.exe,設(shè)置方式如下(Web.config) <sessionState mode='InProc' cookieless='false' timeout='20'/> 由于是直接保存在進(jìn)程中,所以性能最好,但是經(jīng)常會(huì)發(fā)生Session信息丟失,常見(jiàn)的導(dǎo)致進(jìn)程重啟的可能情況為: 配置文件中processModel標(biāo)簽的memoryLimit屬性; Global.asax或者Web.config文件被更改; Bin文件夾中的Web程序(DLL)被修改; 殺毒軟件掃描了一些.config文件; 系統(tǒng)資源緊張進(jìn)行資源回收導(dǎo)致IIS進(jìn)程崩潰或重啟等。 更多信息請(qǐng)參閱http://support.microsoft.com/kb/316148 2. State Server 此種方式是將Session信息存儲(chǔ)在其它的進(jìn)程中而不是IIS中,這樣就可以避免因IIS進(jìn)程崩潰或重啟而導(dǎo)致的Session信息丟失。但是此種方式要求保存在Session的信息必須序列化,然后從Session中獲取的時(shí)候也要反序列化,這就導(dǎo)致性能有略微的損失。 <sessionState mode='StateServer' cookieless='false' timeout='20'/> StateServer是本機(jī)的一個(gè)服務(wù),可以在系統(tǒng)服務(wù)里看到服務(wù)名為ASP.NET State Service的服務(wù),默認(rèn)情況是不啟動(dòng)的。當(dāng)我們?cè)O(shè)定mode為StateServer之后,請(qǐng)把該服務(wù)的啟動(dòng)模式設(shè)置為自動(dòng)(這樣下次服務(wù)就可以隨機(jī)器而啟動(dòng))并手工將該服務(wù)啟動(dòng)運(yùn)行。這樣,我們就能利用本機(jī)的StateService來(lái)存儲(chǔ)Session了,除非電腦重啟或者StateService崩掉,否則Session是不會(huì)丟的。 <sessionState mode='StateServer' stateConnectionString='tcpip=127.0.0.1:42424' cookieless='false' timeout='20'/> 此種配置和上面是一樣的(多了個(gè)stateConnectionString,換句話說(shuō)127.0.0.1是默認(rèn)本機(jī)IP,42424默認(rèn)是該服務(wù)的訪問(wèn)端口號(hào),寫(xiě)不寫(xiě)效果是一樣的),都表示StateServer是在本機(jī)(注:StateServer模式是支持遠(yuǎn)程主機(jī)服務(wù)的,配置類(lèi)似與下面) <sessionState mode='StateServer' stateConnectionString='tcpip=10.7.10.87:42424' cookieless='false' timeout='20'/> 注:如果在啟動(dòng)ASP.NET State Service服務(wù)時(shí)遇到問(wèn)題0x8007277a 即無(wú)法啟動(dòng)或初始化,請(qǐng)嘗試在命令行(CMD)中輸入netsh winsock reset(有可能是winsock的問(wèn)題,所以需reset一下) 3. SQL Server 此種方式是把Session信息保存在SQL Server的數(shù)據(jù)庫(kù)中,也需要序列化,性能有較大損失,但是Session一般不會(huì)發(fā)生丟失的情況,除非SQL Server宕機(jī)。而且此種方式也可以實(shí)現(xiàn)在Web Farm中的Session信息共享(上面兩種方式都不可以)。 <sessionState mode='SQLServer' sqlConnectionString ='data source=10.7.11.114; user id=session_user; password=Session@Pwd' timeout='20' /> 3.1 安裝ASPState數(shù)據(jù)庫(kù) 在使用之前,我們要安裝配置對(duì)應(yīng)的數(shù)據(jù)庫(kù),而微軟給我們提供了一整套方案(你也可以選擇使用自己的數(shù)據(jù)庫(kù)或自己實(shí)現(xiàn)配置和管理)。ASP.NET 2.0版本后微軟提供了aspnet_regsql.exe工具可以方便的配置Session數(shù)據(jù)庫(kù),該工具位于 Web 服務(wù)器上的'系統(tǒng)根目錄\Microsoft.NET\Framework\版本號(hào)'文件夾中. 使用舉例:aspnet_regsql.exe -S . -U session_user -P Session@Pwd -ssadd -sstype p -S參數(shù):表示數(shù)據(jù)庫(kù)實(shí)例名稱. 可以用'.'表示本機(jī),你也可以指定機(jī)器,如10.7.11.110等 -U和-P參數(shù):表示用戶名和密碼. -E參數(shù):可以再-U –P 與 -E中選擇一組. –E表示以當(dāng)前系統(tǒng)用戶通過(guò)windows身份驗(yàn)證登錄數(shù)據(jù)庫(kù), -U -P則是使用SqlServer用戶登錄數(shù)據(jù)庫(kù). -ssadd / –ssremove 參數(shù): -ssadd表示是添加Session數(shù)據(jù)庫(kù), -ssremove表示移除Session數(shù)據(jù)庫(kù). sstype 參數(shù):選項(xiàng) 說(shuō)明 t 將會(huì)話數(shù)據(jù)存儲(chǔ)到 SQL Server tempdb 數(shù)據(jù)庫(kù)中。這是默認(rèn)設(shè)置。如果將會(huì)話數(shù)據(jù)存儲(chǔ)到 tempdb 數(shù)據(jù)庫(kù)中,則在重新啟動(dòng) SQL Server 時(shí)將丟失會(huì)話數(shù)據(jù)。 p 將會(huì)話數(shù)據(jù)存儲(chǔ)到 ASPState 數(shù)據(jù)庫(kù)中,而不是存儲(chǔ)到 tempdb 數(shù)據(jù)庫(kù)中。 c 將會(huì)話數(shù)據(jù)存儲(chǔ)到自定義數(shù)據(jù)庫(kù)中。如果指定 c 選項(xiàng),則還必須使用 -d 選項(xiàng)包括自定義數(shù)據(jù)庫(kù)的名稱。 注意:如果sstype為t,則在下面的用戶權(quán)限賦予中要授予對(duì)tempdb的dbowner權(quán)限,否則將無(wú)法操作數(shù)據(jù)庫(kù)。 3.2 建立連接數(shù)據(jù)庫(kù) ASPState 的用戶,并為此用戶授權(quán) 運(yùn)行 SQL Server 的企業(yè)管理器 展開(kāi)數(shù)據(jù)庫(kù)的安全性 右擊'登錄' 新建'登錄' 輸入'名稱' 選擇 'SQL Server 身份驗(yàn)證' 輸入'密碼' 指定'數(shù)據(jù)庫(kù)' 點(diǎn)擊'數(shù)據(jù)庫(kù)訪問(wèn)' 勾選 'ASPState' 選中'db_owner'角色 點(diǎn)擊'確定' 再一次輸入'密碼' 點(diǎn)擊'確定' 后即可建立 ASPState 的用戶,下面用命令實(shí)現(xiàn): --新建數(shù)據(jù)庫(kù)賬號(hào) SessionStateUser ,默認(rèn)登錄 ASPState use ASPState --切換 DataBase 3.3 啟動(dòng)SQL Server Agent 自動(dòng)運(yùn)行Job ASPState_Job_DeleteExpiredSessions刪除過(guò)期的Session,否則數(shù)據(jù)庫(kù)中的數(shù)據(jù)將一直增長(zhǎng)。 四、Session客戶端配置 再次說(shuō)明,Session的實(shí)現(xiàn)分為兩個(gè)部分:客戶端和服務(wù)器端,其中客戶端負(fù)責(zé)產(chǎn)生SessionId,服務(wù)器端負(fù)責(zé)保存具體的內(nèi)容,這兒所說(shuō)的Session客戶端配置其實(shí)是想說(shuō)說(shuō)關(guān)于SessionId的一些東西。 1. Session在客戶端是如何實(shí)現(xiàn)的? 前面已經(jīng)說(shuō)過(guò),Session在客戶端是通過(guò)產(chǎn)生SessionId來(lái)實(shí)現(xiàn)的,至于這個(gè)SessionId又是通過(guò)什么方式回傳之服務(wù)器從而獲得具體的Session內(nèi)容,前面也略有說(shuō)明,兩種方式:Cookie和Url,由于Url的方式會(huì)導(dǎo)致安全性問(wèn)題,所以現(xiàn)在一般已不再使用此種方式。 當(dāng)系統(tǒng)是用Session的時(shí)候,系統(tǒng)將自動(dòng)在客戶端產(chǎn)生一個(gè)Cookie,名稱為ASP.NET_SessionId,為了便于區(qū)別,我們暫且將此Cookie稱為Session Cookie 2. Session Cookie何時(shí)失效? 和一般的Cookie一樣,默認(rèn)是保存在瀏覽器的內(nèi)存中,當(dāng)瀏覽器關(guān)閉時(shí)失效,如果想此Cookie保存在本地磁盤(pán),可通過(guò)設(shè)置其Expires屬性來(lái)達(dá)到,這種方式現(xiàn)在也被廣泛應(yīng)用于網(wǎng)站的登錄,即用戶在登錄的時(shí)候選擇記住我或保持登錄一段時(shí)間,這樣當(dāng)用戶下次再次訪問(wèn)的時(shí)候就無(wú)需再次輸入用戶名密碼從而達(dá)到快速訪問(wèn)的目的 HttpCookie httpCookie = new HttpCookie('ASP.NET_SessionId', Request.Cookies['ASP.NET_SessionId'].Value); httpCookie.Expires = DateTime.Now.AddMinutes(20); Response.Cookies.Add(httpCookie); if (!string.IsNullOrEmpty(Request.Cookies['ASP.NET_SessionId'].Value)) { //...處理相關(guān)登錄驗(yàn)證等信息 Response.Redirect('Default.aspx?UserName=' loginUser.UserName ''); } 3. Session Cookie失效時(shí)Session失效嗎? 答案當(dāng)然是否定的,記?。篠ession Cookie和Session的失效沒(méi)有任何必然的聯(lián)系,因?yàn)樗鼈兪У幕鶞?zhǔn)或者條件根本不一樣,Session Cookie的失效時(shí)間取決于客服端Cookie的失效時(shí)間,如果是保存在瀏覽器中,那么關(guān)閉瀏覽器Session Cookie就將失效,否則如果保存在本地磁盤(pán),則取決于該Session Cookie設(shè)置的過(guò)期時(shí)間;而服務(wù)器端的Session是保存在服務(wù)器端的,它的失效與否與其服務(wù)器端的設(shè)置和Session的過(guò)期時(shí)間有關(guān)(下面的討論將忽略過(guò)期時(shí)間這個(gè)因數(shù),你懂的),如果是InProc方式,那么當(dāng)承載的IIS進(jìn)程如果奔潰或重啟等都會(huì)丟失;如果是State Server,同樣如果這個(gè)Service宕掉,那Session也會(huì)丟失;而如果是SQL Server,則會(huì)寫(xiě)入數(shù)據(jù)庫(kù),如果你不刪除它,它甚至可以一直存在而永不丟失(事實(shí)是SQL Server Agent會(huì)自動(dòng)運(yùn)行一個(gè)Job刪除過(guò)期的Session);而當(dāng)如果我們使用自定義的數(shù)據(jù)庫(kù)來(lái)保存Session時(shí),你將獲得充分的控制。 4. Session Cookie何時(shí)產(chǎn)生?刷新頁(yè)面其值會(huì)改變嗎? 牢記一點(diǎn),只有當(dāng)使用Session的時(shí)候才會(huì)產(chǎn)生Session Cookie。你也許會(huì)反問(wèn)那為什么當(dāng)配置Session模式為SQLServer時(shí),就算沒(méi)有使用Session,也可以獲得ASP.NET_SessionId的值,即在Page_Load的時(shí)候執(zhí)行方法Response.Write(Request.Cookies['ASP.NET_SessionId'].Value),會(huì)輸出值,我的猜測(cè)是雖然你可以獲得ASP.NET_SessionId值,但實(shí)際上并沒(méi)有真正產(chǎn)生Session Cookie,因?yàn)榇藭r(shí)當(dāng)我試圖通過(guò)HttpWatch(下面介紹的工具)來(lái)查看此Session Cookie的時(shí)候根本查不到,當(dāng)然這也只是我的個(gè)人猜測(cè)而已,至于具體的內(nèi)部機(jī)制還是不甚了解。 當(dāng)沒(méi)有使用Session的時(shí)候刷新頁(yè)面Session Cookie的值會(huì)變化嗎?答案是會(huì)的,測(cè)試方法如上,設(shè)置Session模式為SQLServer,在Page_Load的時(shí)候輸出Session Cookie的值,然后一直F5頁(yè)面即可,你會(huì)看到其值一直在變化,直到在代碼中明確地使用Session后便不再變化。 public partial class Login : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { Response.Write(Request.Cookies['ASP.NET_SessionId'].Value); } protected void tbnLogin_Click(object sender, EventArgs e) { if (!string.IsNullOrEmpty(this.txtUserName.ToString()) && !string.IsNullOrEmpty(this.txtPassword.ToString())) { LoginUser loginUser = new LoginUser(); loginUser.UserId = Guid.NewGuid().ToString('N'); loginUser.UserName = this.txtUserName.Text; loginUser.UserPassword = this.txtPassword.Text; Session['LoginUser'] = loginUser; } } } 5. Session Cookie如何查看 如果設(shè)置了Session Cookie的過(guò)期時(shí)間,則此Session Cookie會(huì)保存在本地磁盤(pán),一般是在目錄C:\Documents and Settings\user\Local Settings\Temporary Internet Files,此目錄可手工設(shè)置(Internet選項(xiàng)->常規(guī)->瀏覽歷史記錄中的'設(shè)置'選項(xiàng)->Internet臨時(shí)文件的'查看文件'選項(xiàng))。 如果沒(méi)有設(shè)置過(guò)期時(shí)間,則Session Cookie默認(rèn)是保存在瀏覽器內(nèi)存中的,Chrome瀏覽器默認(rèn)支持查看Cookie,具體步驟如下:Tools - > Settings ->Show Advanced Settings -> Privacy -> Content Settings -> Cookies -> All cookies and site data,不過(guò)坑爹的是它只支持查看和刪除,不支持修改,如果你想修改的話,我們只能通過(guò)第三方插件來(lái)完成https://chrome.google.com/webstore/detail/fngmhnnpilhplaeedifhccceomclgfbg(Chrome Web Store瀏覽下載安裝即可) 如果你使用的是IE瀏覽器,你也要通過(guò)安裝插件HttpWatch來(lái)查看(Firefox也適用) 五、Session的其它相關(guān)問(wèn)題 1. 如何捕獲Global.asax中的Session_End()事件? |
|
來(lái)自: Levy_X > 《JAVAWEB學(xué)習(xí)資料》