成功開發 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 文件的無會話配置,照樣串行處理請求。