ASP系列講座(十九)管理會話
作者:Eve Cole
更新時間:2009-05-30 19:58:38
成功開發Web 應用程式的難題之一是在一次使用者訪問,即會話期間,當使用者在一個應用程式的頁與頁之間跳轉的同時,維護使用者資訊。 HTTP 是一種無狀態協議,也就是說,Web 伺服器將某頁的每次訪問都當作相互無關的訪問來處理;伺服器不保留前一次訪問的任何信息,即使訪問就發生在當前訪問的幾秒鐘之前。正因為這種不記憶先前存取的特性使得編寫線上目錄之類的應用程式很困難,此類應用程式可能需要追蹤使用者在目錄的不同頁間跳轉的同時曾選擇過的目錄項目。
ASP 提供了一個管理會話資訊問題的獨特方案。使用ASP Session 物件和由您的伺服器產生的特殊使用者ID,您可以建立一個智慧型應用程序,該應用程式可以識別每個來訪的使用者並收集應用程式追蹤使用者的首選項或選擇內容所要用到的信息。
ASP 透過HTTP cookie 設定使用者ID。 HTTP cookie 是儲存在使用者瀏覽器上的小型檔案。因此,如果您正在為不支援cookie 的瀏覽器建立應用程序,或者您的客戶將瀏覽器設定為不接受cookie,請不要使用ASP 的會話管理功能。
您也可以編寫在應用程式啟動或結束時執行的腳本。
啟動和結束會話會話可以透過三種方式啟動:
一個新使用者請求存取一個URL,該URL 標識了某個應用程式中的.asp 文件,並且該應用程式的Global.asa 文件包含Session_OnStart 過程。
使用者在Session 物件中儲存了一個值。
使用者請求了一個應用程式的.asp 文件,並且該應用程式的Global.asa 檔案使用<OBJECT> 標籤建立帶有會話作用域的物件的實例。
如果使用者在指定時間內沒有請求或刷新應用程式中的任何頁,會話將自動結束。這段時間的預設值是20 分鐘。可以透過在Internet 服務管理員中設定「應用程式選項」屬性頁中的「會話逾時」屬性來改變應用程式的預設逾時限制設定。應依據您的Web 應用程式的要求和伺服器的記憶體空間來設定此值。例如,如果您希望瀏覽您的Web 應用程式的使用者在每一頁僅停留幾分鐘,就應該縮短會話的預設逾時值。過長的會話逾時值將導致開啟的會話過多而耗盡您的伺服器的記憶體資源。
對於一個特定的會話,如果您想要設定一個小於預設逾時值的逾時值,可以設定Session 物件的Timeout 屬性。例如,下面這段腳本將逾時值設定為5 分鐘。
<% Session.Timeout = 5 %>
您也可以設定大於預設值的逾時值,Session.Timeout 屬性決定逾時值。
您也可以透過Session 物件的Abandon 方法明確結束一個會話。例如,在表格中提供一個「退出」按鈕,將按鈕的ACTION 參數設定為包含下列指令的.asp 檔案的URL 。
<% Session.Abandon %>
關於SessionID 和Cookie
當使用者第一次請求給定的應用程式中的.asp 檔案時,ASP 會產生一個SessionID。 SessionID 是由一個複雜演算法產生的號碼,它唯一標識每個使用者會話。在新會話開始時,伺服器將Session ID 作為一個cookie 儲存在使用者的Web 瀏覽器中。
SessionID 與鑰匙很相似,當會話期間使用者與應用程式互動時,ASP 可以將使用者資訊儲存在伺服器的一個「保險箱」中。正像用鑰匙能存取保險箱中物品一樣,透過在HTTP 請求標題中發送的用戶SessionID cookie,就能夠對該「保險箱」中的內容進行存取。每當ASP 收到一個頁請求時,就檢查HTTP 請求標題,以獲得SessionID cookie。
在將SessionID cookie 儲存於使用者的瀏覽器之後,即使使用者請求了另一個.asp 文件,或請求了運行在另一個應用程式中的.asp 文件,ASP 仍會重複使用該cookie 追蹤會話。與此相似,如果使用者故意放棄會話或讓會話逾時,然後再請求另一個.asp 文件,那麼ASP 將以同一個cookie 開始新的會話。只有當伺服器管理員重新啟動伺服器或使用者重新啟動Web 瀏覽器時,此時儲存在記憶體中的SessionID 設定將被清除,使用者將會獲得新的SessionID cookie。
透過重複使用SessionID cookie,ASP 將傳送給使用者瀏覽器的cookie 數量降至最低。另外,如果您決定您的ASP 應用程式不需要會話管理,就可以不讓ASP 追蹤會話並向使用者傳送SessionID 。
ASP 在下列情況下不會傳送會話的cookie:
應用程式的會話狀態已停用。
ASP 頁定義為無會話,即該頁包含<%@ EnableSessionState=False %> 標記。
請注意,SessionID cookie 並未提供追蹤使用者對某個Web 網站的多次造訪的永久方法。儲存在伺服器記憶體中的SessionID 資訊很容易遺失。如果想要追蹤在很長一段時間內存取您的Web 應用程式的用戶,必須透過在用戶的Web 瀏覽器中儲存一個專門的cookie,並將cookie 資訊儲存到資料庫中來建立一個用戶識別碼。
在Session 物件中儲存數據
Session 物件提供了一個可在其中儲存資訊的動態關聯數組。您可以在Session 物件中儲存數值變數和物件變數。
透過對Session 物件中的命名項賦值,可將變數儲存在Session 物件中。例如,以下命令將兩個新變數儲存在Session 物件中:
<%
Session("FirstName") = "Jeff"
Session("LastName") = "Smith"
%>
透過存取該命名項可從Session 物件中取得資訊。例如,顯示Session("FirstName") 的目前值:
Welcome <%= Session("FirstName") %>
可以在Session 物件中儲存使用者的首選項,然後透過存取首選項來決定將哪一頁傳送給使用者。例如,可以允許使用者在您的應用程式的第一頁中指定純文字版本的內容並將此選擇套用到使用者此後對該應用程式的所有頁面的存取。
<% If Session("ScreenResolution") = "Low" Then %>
This is the text version of the page.
<% Else %>
This is the multimedia version of the page.
<% End If %>
您也可以在Session 物件中儲存一個物件實例,但這樣做會影響伺服器的效能。
管理Web Farm 的會話
ASP 會話資訊儲存在Web 伺服器中。瀏覽器必須向Web 伺服器請求頁面才能取得用來存取會話資訊的腳本。在Web Farm(其中許多Web 伺服器共同承擔響應用戶申請的責任)中,用戶的請求並不總是被路由到同一個伺服器,而是由一個被稱為「負載平衡」進程的特殊軟體對此URL站點的申請分配任一個空閒的伺服器。負載平衡進程使在Web Farm 中保存會話資訊變得更加困難。
為了在一個負載被平衡的網站上使用ASP 會話管理,必須確保使用者會話的所有請求都被導向到同一個Web 伺服器。一種做法是編寫一個Session_OnStart 過程,此過程使用Response 物件將瀏覽器重新導向到執行該使用者會話的Web 伺服器。如果在您的應用程式頁面中的所有連結都是相對的,那麼以後對某一頁的所有請求都將被路由到同一個伺服器。
例如,某使用者要透過要求某一網站的通用URL:http://www.microsoft.com 來存取一個應用程式。負載平衡進程將申請路由到伺服器server3.microsoft.com。 ASP 在此伺服器上產生了一個新的使用者會話。在Session_OnStart 過程中,瀏覽器被重定向給指定的伺服器:
<% Response.Redirect("http://server3.microsoft.com/webapps/firstpage.asp") %>
瀏覽器將請求指定的頁,並且以後的所有請求都將被路由到同一個伺服器。
使用Cookie
cookie 是Web 伺服器嵌入在使用者的Web 瀏覽器中,用來代表使用者的令牌。當下次同一瀏覽器請求一頁時,它將發送從Web 伺服器收到的cookie。 cookie 允許有一組資訊與使用者關聯。 ASP 腳本使用Response 和Request 物件的Cookies 集合,可以取得和設定cookie 的值。
設定cookie
若要設定cookie 的值,可使用Response.Cookies。如果cookie 不存在,Response.Cookies 將建立新的cookie。例如,要傳送一個有關聯值("Mars") 的cookie 名("planet"),可使用下列指令,這些指令必須出現在您的Web 頁的<HTML> 標籤前:
<% Response.Cookies("planet")="Mars" %>
如果您只希望cookie 在目前的使用者工作階段中被使用,則只需向瀏覽器傳送cookie。但是,如果要在用戶已經終止或重新啟動瀏覽器之後確認用戶,就必須強制瀏覽器將cookie 儲存在電腦的硬碟上。若要儲存cookie,可使用Response.Cookies 的Expires 屬性並將日期設定為此後的某一天:
<%
Response.Cookies("planet") = "Mars"
Response.Cookies("planet").Expires = "January 1, 1999"
%>
cookie 可有多個值;這樣的cookie 稱為一個有索引的cookie。每個cookie 值都會被賦予一個關鍵字;您可以設定一個特定的cookie 關鍵字的值。例如:
<% Response.Cookies("planet")("Mars")="SpaceMissions" %>
如果某個現有的cookie 具有關鍵字值但Response.Cookies 未指明一個關鍵字的名稱,則該關鍵字值將會被刪除。類似的,如果某個現有的cookie 沒有關鍵字值但Response.Cookies 指明了關鍵字的名稱和值,則現有的cookie 值將被刪除,並產生新的key-value 對。
取得cookie
若要取得cookie 的值,可使用Request.Cookies 集合。例如,如果使用者的HTTP 請求設定了planet=Mars,則下列語句將取得值Mars:
<%= Request.Cookies("planet") %>
相似的,要從有索引的cookie 中取得關鍵字值,可使用關鍵字名。例如,如果使用者發出下列的HTTP 請求:
planet=Mars&Mars=SpaceMissions
下列腳本將傳回值SpaceMissions:
<%= Request.Cookies("planet")("Mars") %>
設定cookie 路徑由ASP 儲存在使用者的Web 瀏覽器中的每個cookie 都包含路徑資訊。當瀏覽器要求的檔案的位置與在cookie 中指定的路徑相同時,瀏覽器會自動將cookie 轉送給伺服器。預設情況下,cookie 路徑與包含最初產生cookie 的.asp 檔案的應用程式名稱對應。例如,如果在名為UserApplication 的應用程式中的.asp 檔案產生了一個cookie,那麼每當使用者的Web 瀏覽器在此應用程式中取得檔案時,除其他在路徑/UserApplication 下的cookie 外,瀏覽器也要將該cookie 轉送給伺服器。
要給cookie 宣告一個不同於預設的應用程式路徑的路徑,可以使用ASP 的Response.Cookies 集合的Path 屬性。例如,下列腳本將路徑SalesApp/Customer/Profiles/ 賦予名為Purchases 的cookie:
<%
Response.Cookies("Purchases") = "12"
Response.Cookies("Purchases").Expires = "January 1, 2001"
Response.Cookies("Purchases").Path = "/SalesApp/Customer/Profiles/"
%>
每當包含Purchases cookie 的Web 瀏覽器要求位於路徑/SalesApp/Customer/Profiles/ 或其子目錄的檔案時,瀏覽器就會將cookie 轉送給伺服器。
許多Web 瀏覽器,包括Microsoft Internet Explorer 4.0 和Netscape 瀏覽器,保留cookie 路徑的大小寫。也就是說,如果一個被要求的檔案的大小寫與保留的cookie 路徑不同,那麼瀏覽器是不會向伺服器轉送cookie 的。例如,對於ASP,虛擬目錄/TRAVEL 和/travel 是相同的ASP 應用程序,而對於保留URL 的大小寫的瀏覽器而言,/TRAVEL 和/travel 則是兩個不同的應用程式。應確保.asp 檔案的所有URL 具有相同的大小寫,以確保使用者的瀏覽器能夠轉送儲存的cookie。
如有需要,可使用下列語句設定cookie 路徑,使得無論應用程式或路徑是什麼,只要使用者的Web 瀏覽器向您的伺服器要求文件,就會轉送cookie :
Response.Cookies("Purchases").Path = "/"
但是,請注意,在不區分應用程式的情況下向伺服器發送cookie,如果cookie 包含不應被指定應用程式以外的程式存取的敏感訊息,就可能產生安全性問題。
不使用cookie 而保留狀態並不是所有的瀏覽器都支援cookie。即便使用支援cookie 的瀏覽器,有些使用者也可能喜歡關閉cookie 支援。如果您的應用程式需要回應不支援cookie 的瀏覽器,就必須使用ASP 會話管理。
如果您不使用ASP 會話管理,就必須編寫您自己的機制以便在您的應用程式頁面之間傳遞訊息。有兩種常規的方法可完成該任務:
在URL 的查詢字串中新增參數。例如:
http://MyServer/MyApp/start.asp?name=Jeff
但是,某些瀏覽器,在表格被以GET 方法提交的情況下會丟棄查詢字串中傳遞的明確參數。
在表格中新增隱含值。例如,下列的HTML 表格包含一個隱含的控制項。此控制項在真正的表格中不出現,而且對使用者的Web 瀏覽器是不可見的。透過HTTP POST 方法,表格除了傳遞使用者提供的資訊外,還傳遞使用者識別。
<FORM METHOD="POST" ACTION="/scripts/inform.asp">
<INPUT TYPE="text" NAME="city" VALUE="">
<INPUT TYPE="text" NAME="country" VALUE ="">
<INPUT TYPE="hidden" NAME="userid" VALUE= <%=UserIDNum(i) %>
<INPUT TYPE="submit" VALUE="Enter">
本方法要求傳輸使用者資訊的所有連結目標被編碼為HTML 表格。
如果您目前沒有使用ASP 會話管理,請關閉您的應用程式會話支援。當會話啟用時,ASP 會向每個請求ASP 頁的瀏覽器傳送SessionID cookie。若要關閉會話支持,可清除Internet 服務管理員中的「應用程式選項」屬性頁中的「啟用會話狀態」複選框。
無會話的ASP 頁
ASP 也提供建立無會話頁的功能,您可以使用該功能將會話的建立時間延後到使用者存取需要會話追蹤的ASP 頁時。
無會話頁不執行以下功能:
執行Session_OnStart 流程。
發送會話ID cookie。
建立Session 物件。
存取以<OBJECT> 標記所建立的內建會話物件或會話作用域物件。
與其他會話請求順序執行。
若要將.asp 配置為無會話,可使用下列語句:
<%@ EnableSessionState=False %>
您應該將此腳本置於.asp 檔案的第一行,位於其他腳本之前。預設情況下,若省略此標記,則啟用會話追蹤。
無會話ASP 頁透過消除潛在的耗時會話操作,改善伺服器的回應效能。例如,考慮以下情況,ASP 頁包含某個幀集中的兩個HTML 幀,幀1 和幀2。幀1 包含一個執行複雜腳本的.asp 文件,而幀2 包含一個簡單的.html 檔案。因為ASP 順序執行(即串行執行)會話請求,所以在幀1 的腳本被執行之前,您將不會看到幀2 的內容。但是,如果您將幀1 設為無會話,則ASP 請求將不再被串列處理,瀏覽器不必等待執行完幀1 的內容即可處理幀2 的內容。
但是,不同幀的多個請求的處理方式最終還要取決於使用者Web 瀏覽器的配置。某些Web 瀏覽器可能不理會您的.asp 檔案的無會話配置,照樣串列處理請求。