[紅]揭開(kāi)ASP.NET中Cookie編程的奧秘

2010-08-28 10:48:35來(lái)源:西部e網(wǎng)作者:

    簡(jiǎn)介

  Cookie 為 Web 應(yīng)用程序保存用戶相關(guān)信息提供了一種有用的方法。例如,當(dāng)用戶訪問(wèn)您的站點(diǎn)時(shí),您可以利用 Cookie 保存用戶首選項(xiàng)或其他信息,這樣,當(dāng)用戶下次再訪問(wèn)您的站點(diǎn)時(shí),應(yīng)用程序就可以檢索以前保存的信息。

  本文概要介紹 Cookie 在 ASP.NET 應(yīng)用程序中的應(yīng)用,為您展示在 ASP.NET 中應(yīng)用 Cookie 的技術(shù)細(xì)節(jié),例如編寫(xiě) Cookie、然后再讀取它們。同時(shí),還將為您介紹 Cookie 的各種特性和各種特殊情況,以及 ASP.NET 對(duì) Cookie 的支持。

  什么是 Cookie?

  Cookie 是一小段文本信息,伴隨著用戶請(qǐng)求和頁(yè)面在 Web 服務(wù)器和瀏覽器之間傳遞。用戶每次訪問(wèn)站點(diǎn)時(shí),Web 應(yīng)用程序都可以讀取 Cookie 包含的信息。

  假設(shè)在用戶請(qǐng)求訪問(wèn)您的網(wǎng)站 www.contoso.com 上的某個(gè)頁(yè)面時(shí),您的應(yīng)用程序發(fā)送給該用戶的不僅僅是一個(gè)頁(yè)面,還有一個(gè)包含日期和時(shí)間的 Cookie。用戶的瀏覽器在獲得頁(yè)面的同時(shí)還得到了這個(gè) Cookie,并且將它保存在用戶硬盤(pán)上的某個(gè)文件夾中。

  以后,如果該用戶再次訪問(wèn)您站點(diǎn)上的頁(yè)面,當(dāng)該用戶輸入 URL www.contoso.com 時(shí),瀏覽器就會(huì)在本地硬盤(pán)上查找與該 URL 相關(guān)聯(lián)的 Cookie。如果該 Cookie 存在,瀏覽器就將它與頁(yè)面請(qǐng)求一起發(fā)送到您的站點(diǎn),您的應(yīng)用程序就能確定該用戶上一次訪問(wèn)站點(diǎn)的日期和時(shí)間。您可以根據(jù)這些信息向用戶發(fā)送一條消息,也可以檢查過(guò)期時(shí)間或執(zhí)行其他有用的功能。

  Cookie 是與 Web 站點(diǎn)而不是與具體頁(yè)面關(guān)聯(lián)的,所以無(wú)論用戶請(qǐng)求瀏覽站點(diǎn)中的哪個(gè)頁(yè)面,瀏覽器和服務(wù)器都將交換 www.contoso.com 的 Cookie 信息。用戶訪問(wèn)其他站點(diǎn)時(shí),每個(gè)站點(diǎn)都可能會(huì)向用戶瀏覽器發(fā)送一個(gè) Cookie,而瀏覽器會(huì)將所有這些 Cookie 分別保存。

  以上就是 Cookie 的基本工作原理。那么,Cookie 有哪些用途呢?最根本的用途是 Cookie 能夠幫助 Web 站點(diǎn)保存有關(guān)訪問(wèn)者的信息。更概括地說(shuō),Cookie 是一種保持 Web 應(yīng)用程序連續(xù)性(即執(zhí)行“狀態(tài)管理”)的方法。瀏覽器和 Web 服務(wù)器除了在短暫的實(shí)際信息交換階段以外總是斷開(kāi)的,而用戶向 Web 服務(wù)器發(fā)送的每個(gè)請(qǐng)求都是單獨(dú)處理的,與其他所有請(qǐng)求無(wú)關(guān)。然而在大多數(shù)情況下,都有必要讓 Web 服務(wù)器在您請(qǐng)求某個(gè)頁(yè)面時(shí)對(duì)您進(jìn)行識(shí)別。例如,購(gòu)物站點(diǎn)上的 Web 服務(wù)器跟蹤每個(gè)購(gòu)物者,以便站點(diǎn)能夠管理購(gòu)物車(chē)和其他的用戶相關(guān)信息。因此 Cookie 的作用就類(lèi)似于名片,它提供了相關(guān)的標(biāo)識(shí)信息,可以幫助應(yīng)用程序確定如何繼續(xù)執(zhí)行。

  使用 Cookie 能夠達(dá)到多種目的,所有這些目的都是為了使 Web 站點(diǎn)記住您。例如,一個(gè)實(shí)施民意測(cè)驗(yàn)的站點(diǎn)可以簡(jiǎn)單地利用 Cookie 作為布爾值,表示您的瀏覽器是否已經(jīng)參與了投票,從而避免您重復(fù)投票; 而那些要求用戶登錄的站點(diǎn)則可以通過(guò) Cookie 來(lái)確定您是否已經(jīng)登錄過(guò),這樣您就不必每次都輸入憑據(jù)。

  有關(guān) Cookie 的更多背景信息,建議您閱讀 Verizon Web 站點(diǎn)中的“How Internet Cookies Work”一文,地址為 http://www22.verizon.com/about/community/learningcenter/articles/displayarticle1/0,4065,1022z1,00.html(英文)。其作者詳細(xì)解釋了什么是 Cookie 以及 Cookie 是如何在瀏覽器和服務(wù)器之間交換信息的,他還全面總結(jié)了 Cookie 涉及的隱私問(wèn)題。

  順便問(wèn)一下,您是否想知道它們?yōu)槭裁幢环Q作“Cookie”?Jargon File(又稱為“The New Hacker's Dictionary”)版本 4.3.3 對(duì)這一術(shù)語(yǔ)的詞源給出了準(zhǔn)確的定義和合理的解釋。您可以在 http://www.catb.org/~esr/jargon/jargon.html#cookie(英文)找到相關(guān)的條目。

  在此后的內(nèi)容中,本文將假設(shè)您已經(jīng)知道什么是 Cookie,并且假設(shè)您已經(jīng)清楚為什么要在 ASP.NET 應(yīng)用程序中使用 Cookie。

    Cookie 的限制

  在開(kāi)始討論 Cookie 的技術(shù)細(xì)節(jié)之前,我想先介紹一下 Cookie 應(yīng)用的幾條限制。大多數(shù)瀏覽器支持最多可達(dá) 4096 字節(jié)的 Cookie,如果要將為數(shù)不多的幾個(gè)值保存到用戶計(jì)算機(jī)上,這一空間已經(jīng)足夠大,但您不能用一個(gè) Cookie 來(lái)保存數(shù)據(jù)集或其他大量數(shù)據(jù)。在實(shí)際應(yīng)用中,您可能并不希望在 Cookie 中保存大量的用戶信息,而只希望保存用戶編號(hào)或其他標(biāo)識(shí)符。之后,當(dāng)用戶再次訪問(wèn)您的站點(diǎn)時(shí),您就可以使用該用戶 ID 在數(shù)據(jù)庫(kù)中查找用戶的詳細(xì)信息。(有關(guān)保存用戶信息的說(shuō)明,請(qǐng)參閱 Cookie 和安全性。)

  瀏覽器還限制了您的站點(diǎn)可以在用戶計(jì)算機(jī)上保存的 Cookie 數(shù)。大多數(shù)瀏覽器只允許每個(gè)站點(diǎn)保存 20 個(gè) Cookie。如果試圖保存更多的 Cookie,則最先保存的 Cookie 就會(huì)被刪除。還有些瀏覽器會(huì)對(duì)來(lái)自所有站點(diǎn)的 Cookie 總數(shù)作出限制,這個(gè)限制通常為 300 個(gè)。

  您最可能遇到的 Cookie 限制是:用戶可以設(shè)置自己的瀏覽器,拒絕接受 Cookie。您很難解決這個(gè)問(wèn)題,除非完全不使用 Cookie 而是通過(guò)其他機(jī)制來(lái)保存用戶相關(guān)信息。保存用戶信息的一種常用方法是會(huì)話狀態(tài),但會(huì)話狀態(tài)又依賴于 Cookie。這一點(diǎn)在后面的 Cookie 和會(huì)話狀態(tài)中闡述。

  注意:有關(guān)狀態(tài)管理和 Web 應(yīng)用程序中用于保存信息的選項(xiàng)的詳細(xì)信息,請(qǐng)參閱 Introduction to Web Forms State(英文)和 State Management Recommendations(英文)。
更一般的經(jīng)驗(yàn)很可能是,盡管 Cookie 在應(yīng)用程序中非常有用,應(yīng)用程序也不應(yīng)該依賴于能夠保存 Cookie。利用 Cookie 可以做到錦上添花,但不要利用它們來(lái)支持關(guān)鍵功能。如果您的應(yīng)用程序必須使用 Cookie,則您可以通過(guò)測(cè)試來(lái)確定瀏覽器是否接受 Cookie。我在本文后面的檢查瀏覽器是否接受 Cookie 一節(jié)中簡(jiǎn)單介紹了一種測(cè)試方法。

  編寫(xiě) Cookie

  您可以利用頁(yè)面的 Response(英文)屬性來(lái)編寫(xiě) Cookie,該屬性提供的對(duì)象使用戶可以將信息添加到由頁(yè)面向?yàn)g覽器呈現(xiàn)的信息中。Response 對(duì)象支持一個(gè)名為 Cookies(英文)的集合,您可以向其中添加要寫(xiě)入瀏覽器的 Cookie。

  注意:下面要討論的 Response 對(duì)象和 Request 對(duì)象分別是包含 HttpResponse(英文)和 HttpRequest(英文)類(lèi)實(shí)例的頁(yè)面的屬性。要在文檔中查找 Response 和 Request 的信息,請(qǐng)參閱 HttpResponse 和 HttpRequest 下的內(nèi)容。

  在創(chuàng)建 Cookie 時(shí),您需要指定幾個(gè)值。最初,您要指定 Cookie 的名稱和其中保存的值。您可以創(chuàng)建多個(gè) Cookie,每個(gè) Cookie 都必須具有唯一的名稱,以便日后讀取時(shí)識(shí)別。(Cookie 是按名稱保存的,所以如果您創(chuàng)建了兩個(gè)名稱相同的 Cookie,后保存的那一個(gè)將覆蓋前一個(gè)。)

  您可能還希望指定 Cookie 的過(guò)期日期和時(shí)間。Cookie 一般都寫(xiě)入到用戶的磁盤(pán),然后可能一直都留在磁盤(pán)上。因此,您可以指定 Cookie 過(guò)期的日期和時(shí)間。當(dāng)用戶再次訪問(wèn)您的站點(diǎn)時(shí),瀏覽器會(huì)先檢查您站點(diǎn)的 Cookie 集合,如果某個(gè) Cookie 已經(jīng)過(guò)期,瀏覽器不會(huì)把這個(gè) Cookie 隨頁(yè)面請(qǐng)求一起發(fā)送給服務(wù)器,而是刪除這個(gè)已經(jīng)過(guò)期的 Cookie。(您的站點(diǎn)可能已經(jīng)在用戶計(jì)算機(jī)上寫(xiě)入了多個(gè) Cookie,每個(gè) Cookie 都有各自的過(guò)期日期和時(shí)間。) 請(qǐng)注意,由瀏覽器負(fù)責(zé)管理硬盤(pán)上的 Cookie,這將影響您在應(yīng)用程序中對(duì) Cookie 的使用,我很快會(huì)介紹這方面的內(nèi)容。

  一個(gè) Cookie 的有效期應(yīng)為多長(zhǎng)?這取決于 Cookie 的用途,換句話說(shuō),取決于您的應(yīng)用程序需要 Cookie 值保持有效的時(shí)間有多長(zhǎng)。如果利用 Cookie 統(tǒng)計(jì)網(wǎng)站的訪問(wèn)者,您可以把有效期設(shè)置為 1 年,如果某個(gè)用戶已有一年時(shí)間未訪問(wèn)您的站點(diǎn),則可以把該用戶當(dāng)作新的訪問(wèn)者; 如果利用 Cookie 來(lái)保存用戶的首選項(xiàng),則可以把其設(shè)置為永遠(yuǎn)有效(例如 50 年后到期),因?yàn)槎ㄆ谥匦略O(shè)置首選項(xiàng)對(duì)用戶而言是比較麻煩的。有時(shí),您可能需要編寫(xiě)在數(shù)秒或數(shù)分鐘內(nèi)即過(guò)期的 Cookie。在本文后面的檢查瀏覽器是否接受 Cookie 一節(jié)中,我列舉了一個(gè)示例,該示例中創(chuàng)建的 Cookie 的實(shí)際有效期就只有幾秒。

  注意:不要忘記用戶隨時(shí)可以刪除自己計(jì)算機(jī)上的 Cookie,所以即使您保存了長(zhǎng)期有效的 Cookie,用戶也可以自行決定將其全部刪除,同時(shí)清除保存在 Cookie 中的所有設(shè)置。

  如果沒(méi)有設(shè)置 Cookie 的有效期,還是可以創(chuàng)建 Cookie,但它不會(huì)保存到用戶的硬盤(pán)上,而是會(huì)成為用戶會(huì)話信息的一部分。如果用戶關(guān)閉瀏覽器或會(huì)話超時(shí),該 Cookie 就會(huì)被刪除。這種非永久性的 Cookie 很適合用來(lái)保存只需短時(shí)間保存的信息,或者保存由于安全原因不應(yīng)該寫(xiě)入客戶計(jì)算機(jī)磁盤(pán)的信息。例如,如果用戶使用的是一臺(tái)公用計(jì)算機(jī),而您不希望把 Cookie 寫(xiě)入這種計(jì)算機(jī)的磁盤(pán)上,這時(shí)就可以使用非永久性的 Cookie。

  您可以通過(guò)多種方法把 Cookie 添加到 Response.Cookies 集合中。以下示例介紹了兩種完成此任務(wù)的方法:

Response.Cookies("userName").Value = "mike"
Response.Cookies("userName").Expires = DateTime.Now.AddDays(1)

Dim aCookie As New HttpCookie("lastVisit")
aCookie.Value = DateTime.Now.ToString
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)


  該示例向 Cookies 集合中添加了兩個(gè) Cookie,一個(gè)稱為“userName”,另一個(gè)稱為“l(fā)astVisit”。對(duì)于第一個(gè) Cookie,我直接設(shè)置了 Response.Cookies 集合的值。您可以使用這種方法向集合中添加值,因?yàn)?Response.Cookies 是從 NameObjectCollectionBase(英文)類(lèi)型的特殊集合派生得到的。

  對(duì)于第二個(gè) Cookie,我創(chuàng)建了 Cookie 對(duì)象的一個(gè)實(shí)例(HttpCookie [英文] 類(lèi)型),并設(shè)置了其屬性,然后通過(guò) Add 方法把它添加到 Response.Cookies 集合。實(shí)例化 HttpCookie 對(duì)象時(shí),您必須把 Cookie 名稱作為構(gòu)造函數(shù)的一部分進(jìn)行傳遞。

  這兩個(gè)示例完成了相同的任務(wù),即向?yàn)g覽器寫(xiě)入一個(gè) Cookie。您要采用哪種方法主要取決于您的個(gè)人喜好。您可能會(huì)發(fā)現(xiàn)第二種方法在設(shè)置 Cookie 屬性方面要稍微容易一些,但同時(shí)您也會(huì)注意到兩者的差別并不是很大。

  在這兩種方法中,有效期值必須為 DateTime 類(lèi)型。而“l(fā)astVisited”值也是日期/時(shí)間值。但在這種情況下,我必須把日期/時(shí)間值轉(zhuǎn)換為字符串,因?yàn)?Cookie 中的任何值最終都是以字符串的形式保存的。

    查看您的 Cookie

  您可能會(huì)發(fā)現(xiàn),了解創(chuàng)建 Cookie 的效果會(huì)對(duì)您很有幫助。而查看 Cookie 是比較容易的,因?yàn)樗鼈兌际俏谋疚募,關(guān)鍵在于您能找到它們。不同的瀏覽器保存 Cookie 的方式也不同。我將介紹 Internet Explorer 是如何保存 Cookie 的。如果您使用的是其他瀏覽器,請(qǐng)查看該瀏覽器的幫助,以了解有關(guān) Cookie 處理方面的知識(shí)。

  查看 Cookie 的一個(gè)簡(jiǎn)便方法是讓 Internet Explorer 為您查找。在 Internet Explorer 中,從“工具”菜單中選擇“Internet 選項(xiàng)”,在“常規(guī)”選項(xiàng)卡中單擊“設(shè)置”,然后單擊“查看文件”。Internet Explorer 將打開(kāi)一個(gè)窗口,顯示所有的臨時(shí)文件,包括 Cookie。在窗口中查找以“Cookie:”開(kāi)頭的文件 或查找文本文件。雙擊一個(gè) Cookie,在默認(rèn)的文本文件中打開(kāi)它。

  您也可以在硬盤(pán)上查找 Cookie 的文本文件,從而打開(kāi) Cookie。Internet Explorer 將站點(diǎn)的 Cookie 保存在文件名格式為 <user>@<domain>.txt 的文件中,其中 <user> 是您的帳戶名。例如,如果您的名稱為 mikepope,您訪問(wèn)的站點(diǎn)為 www.contoso.com,那么該站點(diǎn)的 Cookie 將保存在名為 mikepope@www.contoso.txt 的文件中。(該文件名可能包含一個(gè)順序的編號(hào),如 mikepope@www.contoso[1].txt。)

  這個(gè) Cookie 文本文件是與用戶相關(guān)的,所以會(huì)按照帳戶分別保存。例如,在 Windows XP 中,您可以在如下所示的目錄中找到 Cookie 文件:

c:\Documents and Settings\<user>\Cookies

  要查找最新創(chuàng)建的 Cookie,可以按修改日期對(duì)目錄內(nèi)容進(jìn)行排序,并查找最近修改的文件。

  您可以使用文本編輯器打開(kāi) Cookie。如果該文件包含多個(gè) Cookie,這些 Cookie 之間將用星號(hào) (*) 分隔。每個(gè) Cookie 的第一行是 Cookie 的名稱,第二行是值,其余各行則包含 Cookie 的日常處理信息,例如過(guò)期日期和時(shí)間。Cookie 中還有一個(gè)簡(jiǎn)單的校驗(yàn)和,如果更改 Cookie 名稱或值的長(zhǎng)度,瀏覽器就會(huì)檢測(cè)到修改并刪除該 Cookie。

  多值 Cookie(子鍵)

  以上示例為每個(gè)要保存的值(用戶名、上次訪問(wèn)時(shí)間)都使用了一個(gè) Cookie 。您也可以在一個(gè) Cookie 中保存多個(gè)名稱/值對(duì)。名稱/值對(duì)也稱作“鍵”或“子鍵”,具體取決于您讀取的內(nèi)容。(如果您熟悉 URL 的結(jié)構(gòu),就會(huì)發(fā)現(xiàn)子鍵與其中的查詢字符串非常相象。) 例如,如果不希望創(chuàng)建名為“userName”和“l(fā)astVisit”的兩個(gè)單獨(dú)的 Cookie,可以創(chuàng)建一個(gè)名為“userInfo”的 Cookie,并使其包含兩個(gè)子鍵:“userName”和“l(fā)astVisit”。

  有很多原因會(huì)讓我們用子鍵來(lái)代替單獨(dú)的 Cookie。最顯而易見(jiàn)的是,把相關(guān)或類(lèi)似的信息放在一個(gè) Cookie 中會(huì)比較有條理。另外,由于所有信息都在一個(gè) Cookie 中,所以諸如有效期之類(lèi)的 Cookie 屬性就適用于所有信息。(當(dāng)然,如果要為不同類(lèi)型的信息指定不同的過(guò)期日期,就應(yīng)該把信息保存在單獨(dú)的 Cookie 中。)

  帶有子鍵的 Cookie 還可以幫助您減小 Cookie 的大小。如前面的 Cookie 的限制一節(jié)所述,Cookie 的總大小限制在 4096 字節(jié)以內(nèi),而且不能為一個(gè)網(wǎng)站保存超過(guò) 20 個(gè) Cookie。利用帶子鍵的單個(gè) Cookie,站點(diǎn)的 Cookie 數(shù)量就不會(huì)超過(guò) 20 個(gè)的限制。此外,一個(gè) Cookie 會(huì)占用大約 50 個(gè)字符的基本空間開(kāi)銷(xiāo)(用于保存有效期信息等),再加上其中保存的值的長(zhǎng)度,其總和接近 4K 的限制。如果使用五個(gè)子鍵而不是五個(gè)單獨(dú)的 Cookie,您可以省去四個(gè) Cookie 的基本空間開(kāi)銷(xiāo),總共能節(jié)省大約 200 個(gè)字節(jié)。

  要?jiǎng)?chuàng)建帶子鍵的 Cookie,您可以使用用于編寫(xiě)單個(gè) Cookie 的各種語(yǔ)法。以下示例顯示了編寫(xiě)同一 Cookie 的兩種不同方法,其中的每個(gè) Cookie 都帶有兩個(gè)子鍵:

Response.Cookies("userInfo")("userName") = "mike"
Response.Cookies("userInfo")("lastVisit") = DateTime.Now.ToString
Response.Cookies("userInfo").Expires = DateTime.Now.AddDays(1)

Dim aCookie As New HttpCookie("userInfo")
aCookie.Values("userName") = "mike"
aCookie.Values("lastVisit") = DateTime.Now.ToString
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)


  控制 Cookie 有效范圍

  默認(rèn)情況下,一個(gè)站點(diǎn)的全部 Cookie 都一起保存在客戶機(jī)上,而且所有這些 Cookie 都會(huì)隨著對(duì)該站點(diǎn)發(fā)送的請(qǐng)求一起發(fā)送到服務(wù)器,也就是說(shuō),站點(diǎn)的每個(gè)頁(yè)面都能得到該站點(diǎn)的所有 Cookie。但有時(shí)候,您可能希望 Cookie 更具有針對(duì)性,這時(shí),您可以通過(guò)兩種方法設(shè)置 Cookie 的有效范圍:

  把 Cookie 的有效范圍限制在服務(wù)器上的一個(gè)文件夾中,實(shí)際上這樣就將 Cookie 限制到站點(diǎn)上的某個(gè)應(yīng)用程序。

  把有效范圍設(shè)置為某個(gè)域,從而允許您指定域中的哪些子域可以訪問(wèn) Cookie。

  將 Cookie 限制到某個(gè)文件夾或應(yīng)用程序

  要將 Cookie 限制到服務(wù)器上的某個(gè)文件夾,請(qǐng)按如下方法設(shè)置 Cookie 的 Path 屬性:

Dim appCookie As New HttpCookie("AppCookie")
appCookie.Value = "written " & Now.ToString
appCookie.Expires = Now.AddDays(1)
appCookie.Path = "/Application1"
Response.Cookies.Add(appCookie)


  當(dāng)然,您也可以通過(guò)直接設(shè)置 Response.Cookies 來(lái)編寫(xiě) Cookie,如前文所述。

  路徑可以是站點(diǎn)根目錄下的物理路徑,也可以是虛擬根目錄。這樣一來(lái),Cookie 就只能用于 Application1 文件夾或虛擬根目錄中的頁(yè)面。例如,如果您的站點(diǎn)名為 www.contoso.com,則前面示例中生成的 Cookie 就只能用于路徑為 http://www.contoso.com/Application1/ 的頁(yè)面以及該文件夾下的所有頁(yè)面,而不適用于其他應(yīng)用程序中的頁(yè)面,如 http://www.contoso.com/Application2/ 或 http://www.contoso.com/ 下的頁(yè)面。

  提示:通過(guò)對(duì) Internet Explorer 和 Mozilla 瀏覽器進(jìn)行測(cè)試發(fā)現(xiàn),此處使用的路徑是區(qū)分大小寫(xiě)的。一般而言,Windows 服務(wù)器上的 URL 不區(qū)分大小寫(xiě),但這種情況例外。您無(wú)法控制用戶如何在瀏覽器中輸入 URL,但是,如果您的應(yīng)用程序依賴于與特定路徑相關(guān)的 Cookie,則請(qǐng)確保您所創(chuàng)建的所有超鏈接中的 URL 與 Path 屬性值的大小寫(xiě)相匹配。

  將 Cookie 的有效范圍限制到域

  默認(rèn)情況下,Cookie 與特定的域相關(guān)聯(lián)。例如,如果您的站點(diǎn)是 www.contoso.com,那么當(dāng)用戶向該站點(diǎn)請(qǐng)求頁(yè)面時(shí),您編寫(xiě)的 Cookie 就被發(fā)送到服務(wù)器。(有特定路徑值的 Cookie 除外,我在上一節(jié)剛剛解釋過(guò)。) 如果您的站點(diǎn)有子域(例如 contoso.com、sales.contoso.com 和 support.contoso.com),就可以把 Cookie 同特定的子域相關(guān)聯(lián)。為此,需要設(shè)置 Cookie 的 Domain 屬性,如下所示:

Response.Cookies("domain").Value = DateTime.Now.ToString
Response.Cookies("domain").Expires = DateTime.Now.AddDays(1)
Response.Cookies("domain").Domain = "support.contoso.com"


  如果按照這種方式設(shè)置域,則 Cookie 只能用于指定子域中的頁(yè)面。

  您也可以利用 Domain 屬性來(lái)創(chuàng)建可在多個(gè)子域中共享的 Cookie。例如,對(duì)域進(jìn)行如下設(shè)置:

Response.Cookies("domain").Value = DateTime.Now.ToString
Response.Cookies("domain").Expires = DateTime.Now.AddDays(1)
Response.Cookies("domain").Domain = "contoso.com"


  這樣,該 Cookie 就可用于主域、sales.contoso.com 和 support.contoso.com。

讀取 Cookie

  當(dāng)瀏覽器向服務(wù)器發(fā)送請(qǐng)求時(shí),該服務(wù)器的 Cookie 會(huì)與請(qǐng)求一起發(fā)送。在 ASP.NET 應(yīng)用程序中,您可以使用 Request 對(duì)象來(lái)讀取 Cookie。Request 對(duì)象的結(jié)構(gòu)與 Response 對(duì)象的結(jié)構(gòu)基本相同,所以從 Request 對(duì)象中讀取 Cookie 的方法與向 Response 對(duì)象中寫(xiě)入 Cookie 的方法非常類(lèi)似。以下示例顯示了兩種方法,目的都是獲取名為“username”的 Cookie 的值并將值顯示在 Label 控件中:

If Not Request.Cookies("userName") Is Nothing Then
 Label1.Text = Server.HtmlEncode(Request.Cookies("userName").Value)
End If

If Not Request.Cookies("userName") Is Nothing Then
 Dim aCookie As HttpCookie = Request.Cookies("userName")
 Label1.Text = Server.HtmlEncode(aCookie.Value)
End If


  在獲取 Cookie 的值之前,應(yīng)該確保該 Cookie 確實(shí)存在。否則,您將得到一個(gè) System.NullReferenceException(英文)異常。還需要注意的是,在頁(yè)面中顯示 Cookie 的內(nèi)容之前,我調(diào)用了 HttpServerUtility.HtmlEncode(英文)方法對(duì) Cookie 的內(nèi)容進(jìn)行編碼。之所以這樣做,是因?yàn)槲乙@示 Cookie 的內(nèi)容(一般您不會(huì)這樣做)而且要確保沒(méi)有任何惡意用戶在 Cookie 中添加了可執(zhí)行腳本。有關(guān) Cookie 安全性的詳細(xì)信息,請(qǐng)參閱 Cookie 和安全性。

  注意:由于不同的瀏覽器保存 Cookie 的方式也不同,所以同一臺(tái)計(jì)算機(jī)上的不同瀏覽器不一定能夠相互讀取各自的 Cookie。例如,如果使用 Internet Explorer 測(cè)試一個(gè)頁(yè)面,然后再使用其他瀏覽器進(jìn)行測(cè)試,那么后者就不會(huì)找到 Internet Explorer 保存的 Cookie。當(dāng)然,大多數(shù)人一般都是使用同一種瀏覽器進(jìn)行 Web 交互的,因此在大多數(shù)情況下不會(huì)出現(xiàn)問(wèn)題。但有時(shí)還是會(huì)遇到問(wèn)題,比如您要測(cè)試應(yīng)用程序?qū)g覽器的兼容性。

  讀取 Cookie 中子鍵值的方法與設(shè)置該值的方法類(lèi)似。以下是獲取子鍵值的一種方法:

If Not Request.Cookies("userInfo") Is Nothing Then
 Label1.Text = Server.HtmlEncode(Request.Cookies("userInfo")("userName"))
 Label2.text = Server.HtmlEncode(Request.Cookies("userInfo")("lastVisit"))
End If


  在上面的示例中,我獲取的是子鍵“l(fā)astVist”的值,在此前的討論中我把該值設(shè)置為 DateTime 值的字符串表示形式。請(qǐng)記住,Cookie 是用字符串的形式保存值的,所以要將 lastVisit 值用作日期,就必須對(duì)其進(jìn)行轉(zhuǎn)換:

Dim dt As DateTime
dt = CDate(Request.Cookies("userInfo")("lastVisit"))


  Cookie 中子鍵的類(lèi)型是 NameValueCollection(英文)類(lèi)型的集合。因此,另一種獲取單個(gè)子鍵的方法是先獲取子鍵集合,然后按名稱提取子鍵的值,如下所示:

If Not Request.Cookies("userInfo") Is Nothing Then
 Dim UserInfoCookieCollection As _
System.Collections.Specialized.NameValueCollection
 UserInfoCookieCollection = Request.Cookies("userInfo").Values
 Label1.Text = Server.HtmlEncode(UserInfoCookieCollection("userName"))
 Label2.Text = Server.HtmlEncode(UserInfoCookieCollection("lastVisit"))
End If


  就像設(shè)置 Cookie 一樣,使用哪種方法讀取 Cookie 也由您自己決定。



  什么是有效期?

  您可以讀取 Cookie 的名稱和值,除此以外,需要了解的有關(guān) Cookie 的信息并不是很多。雖然您可以獲取 Domain 和 Path 屬性,但是這些屬性的用途很有限。例如,您可以讀取 Domain 屬性,但如果您的頁(yè)面與 Cookie 不在相同的域,您根本就不會(huì)在頁(yè)面的位置接收到該 Cookie。

  您無(wú)法讀取的是 Cookie 的過(guò)期日期和時(shí)間。事實(shí)上,當(dāng)瀏覽器向服務(wù)器發(fā)送 Cookie 信息時(shí),瀏覽器并未將過(guò)期信息包括在內(nèi)。您可以讀取 Expires 屬性,但總是返回為零的日期/時(shí)間值。

  在前面的編寫(xiě) Cookie 一節(jié)中,我已經(jīng)講過(guò),是瀏覽器負(fù)責(zé)管理 Cookie 的,Expires 屬性就很好地印證了這一點(diǎn)。Expires 屬性的主要作用是幫助瀏覽器執(zhí)行有關(guān) Cookie 保存的日常管理。從服務(wù)器的角度來(lái)看,Cookie 要么存在要么不存在,所以對(duì)服務(wù)器而言,有效期并不是有用的信息。所以,瀏覽器在發(fā)送 Cookie 時(shí)并不提供此信息。如果您需要 Cookie 的過(guò)期日期,就必須重新設(shè)置,關(guān)于這一點(diǎn)我將在修改和刪除 Cookie 中介紹。

  更確切地說(shuō),您可以在向?yàn)g覽器發(fā)送 Cookie 之前讀取已在 Response 對(duì)象中設(shè)置的 Expires 屬性,但您無(wú)法從返回的 Request 對(duì)象中獲取有效期信息。

讀取 Cookie 集合

  前面的示例假設(shè)您要讀取名稱已知的 Cookie。有時(shí),您可能需要讀取可供頁(yè)面使用的所有 Cookie。要讀取可供頁(yè)面使用的所有 Cookie 的名稱和值,您可以利用如下代碼遍歷 Request.Cookies 集合:

Dim i As Integer
Dim output As String = ""
Dim aCookie As HttpCookie
For i = 0 to Request.Cookies.Count - 1
 aCookie = Request.Cookies(i)
 output &= "Cookie 名稱 = " & Server.HtmlEncode(aCookie.Name) & "<br>"
 output &= "Cookie 值 = " & Server.HtmlEncode(aCookie.Value) & _
& "<br><br>"
Next
Label1.Text = output

  注意:運(yùn)行此代碼時(shí),您很可能會(huì)看到一個(gè)名為“ASP.NET_SessionId”的 Cookie,ASP.NET 用這個(gè) Cookie 來(lái)保存您的會(huì)話的唯一標(biāo)識(shí)符。這個(gè)會(huì)話 Cookie 不會(huì)永久保存到您的硬盤(pán)上。有關(guān)會(huì)話 Cookie 的詳細(xì)信息,請(qǐng)參閱本文后面的 Cookie 和會(huì)話狀態(tài)。
前面的示例有一個(gè)限制:如果 Cookie 有子鍵,就會(huì)以一個(gè)單獨(dú)的名稱/值字符串來(lái)顯示子鍵。Cookie 的 HasKeys(英文)屬性可以告訴您該 Cookie 是否有子鍵。如果有子鍵,您可以在子鍵集合中向下鉆取,獲取各個(gè)子鍵的名稱和值。

  如前文所述,您可以從 Cookie 屬性 Values(英文)中獲取有關(guān)子鍵的信息,該屬性是類(lèi)型 NameValueCollection 的集合。您可以根據(jù)索引值從 Values 集合中直接讀取子鍵值。相應(yīng)的子鍵值可以從 Values 集合的成員 AllKeys(英文)中得到,該成員將返回一個(gè)字符串集合。

  以下示例是對(duì)前一示例的修改。示例中使用 HasKeys 屬性來(lái)測(cè)試子鍵,如果檢測(cè)到子鍵,就從 Values 集合中獲取子鍵:

Dim i As Integer
Dim j As Integer
Dim output As String = ""
Dim aCookie As HttpCookie
Dim subkeyName As String
Dim subkeyValue As String
For i = 0 To Request.Cookies.Count - 1
 aCookie = Request.Cookies(i)
 output &= "名稱 = " & aCookie.Name & "<br>"
 If aCookie.HasKeys Then
  For j = 0 To aCookie.Values.Count - 1
   subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys(j))
   subkeyValue = Server.HtmlEncode(aCookie.Values(j))
   output &= "子鍵名稱 = " & subkeyName & "<br>"
   output &= "子鍵值 = " & subkeyValue & "<br><br>"
  Next
 Else
  output &= "值 = " & Server.HtmlEncode(aCookie.Value) & "<br><br>"
 End If
Next
Label1.Text = output

  您也可以把子鍵作為 NameValueCollection 對(duì)象進(jìn)行提取,如下所示:

If aCookie.HasKeys Then
Dim CookieValues As _
System.Collections.Specialized.NameValueCollection = aCookie.Values
Dim CookieValueNames() As String = CookieValues.AllKeys
For j = 0 To CookieValues.Count – 1
 subkeyName = Server.HtmlEncode(CookieValueNames(j))
 subkeyValue = Server.HtmlEncode(CookieValues(j))
 output &= "子鍵名稱 = " & subkeyName & "<br>"
 output &= "子鍵值 = " & subkeyValue & "<br><br>"
Next
Else
 output &= "值 = " & aCookie.Value & "<br><br>"
End If

  注意:請(qǐng)記住,我之所以調(diào)用 Server.HtmlEncode 方法,只是因?yàn)槲乙陧?yè)面上顯示 Cookie 的值。如果您只是測(cè)試 Cookie 的值,就不必在使用前對(duì)其進(jìn)行編碼。

  修改和刪除 Cookie

  有時(shí),您可能需要修改某個(gè) Cookie,更改其值或延長(zhǎng)其有效期。(請(qǐng)記住,由于瀏覽器不會(huì)把有效期信息傳遞到服務(wù)器,所以您無(wú)法讀取 Cookie 的過(guò)期日期。)

  當(dāng)然,實(shí)際上您并不是直接更改 Cookie。盡管您可以從 Request.Cookies 集合中獲取 Cookie 并對(duì)其進(jìn)行操作,但 Cookie 本身仍然存在于用戶硬盤(pán)上的某個(gè)地方。因此,修改某個(gè) Cookie 實(shí)際上是指用新的值創(chuàng)建新的 Cookie,并把該 Cookie 發(fā)送到瀏覽器,覆蓋客戶機(jī)上舊的 Cookie。

  以下示例說(shuō)明了如何更改用于儲(chǔ)存站點(diǎn)訪問(wèn)次數(shù)的 Cookie 的值:

Dim counter As Integer
If Request.Cookies("counter") Is Nothing Then
 counter = 0
Else
 counter = CInt(Request.Cookies("counter").Value)
End If
counter += 1
Response.Cookies("counter").Value = counter.ToString
Response.Cookies("counter").Expires = DateTime.Now.AddDays(1)

  或者:

Dim ctrCookie As HttpCookie
Dim counter As Integer
If Request.Cookies("counter") Is Nothing Then
 ctrCookie = New HttpCookie("counter")
Else
 ctrCookie = Request.Cookies("counter")
End If
counter = CInt(ctrCookie.Value) + 1
ctrCookie.Value = counter.ToString
ctrCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(ctrCookie)
刪除 Cookie

  刪除 Cookie(即把該 Cookie 從用戶的硬盤(pán)上物理刪除)是修改 Cookie 的一種形式。由于 Cookie 位于用戶的計(jì)算機(jī)中,所以您無(wú)法直接將其刪除。但是,您可以讓瀏覽器為您刪除 Cookie。修改 Cookie 的方法前面已經(jīng)介紹過(guò)(即用相同的名稱創(chuàng)建一個(gè)新的 Cookie),不同的是將其有效期設(shè)置為過(guò)去的某個(gè)日期。當(dāng)瀏覽器檢查 Cookie 的有效期時(shí),就會(huì)刪除這個(gè)已過(guò)期的 Cookie。

  所以,刪除 Cookie 的方法與創(chuàng)建該 Cookie 的方法是相同的,只不過(guò)要把其有效期設(shè)置為過(guò)去的某個(gè)日期。以下示例比刪除單個(gè) Cookie 要稍微有趣一些,它使用的方法可以刪除當(dāng)前域的所有 Cookie:

Dim i As Integer
Dim cookieName As String
Dim limit As Integer = Request.Cookies.Count - 1
For i = 0 To limit
 aCookie = Request.Cookies(i)
 aCookie.Expires = DateTime.Now.AddDays(-1)
 Response.Cookies.Add(aCookie)
Next

  修改或刪除子鍵

  修改單個(gè)子鍵的方法與最初創(chuàng)建它的方法相同:

Response.Cookies("userInfo")("lastVisit") = DateTime.Now.ToString
Response.Cookies("userInfo").Expires = DateTime.Now.AddDays(1)

  比較復(fù)雜的問(wèn)題是如何刪除單個(gè)子鍵。您不能只是簡(jiǎn)單地重新設(shè)置 Cookie 的過(guò)期日期,因?yàn)檫@樣只能刪除整個(gè) Cookie 而不能刪除單個(gè)子鍵。實(shí)際的解決方案是對(duì)包含子鍵的 Cookie 的 Values 集合進(jìn)行操作。首先,通過(guò)從 Request.Cookies 對(duì)象中獲取 Cookie 來(lái)重新創(chuàng)建 Cookie。然后,您就可以調(diào)用 Values 集合的 Remove 方法,將要?jiǎng)h除的子鍵名稱傳遞到 Remove 方法。接下來(lái),您通?梢詫⑿薷暮蟮 Cookie 添加到 Response.Cookies 集合,以便將修改后的 Cookie 發(fā)送回瀏覽器。

  以下代碼顯示了如何刪除子鍵。在示例中,要?jiǎng)h除的子鍵的名稱在變量中指定。

Dim subkeyName As String
subkeyName = "userName"
Dim aCookie As HttpCookie = Request.Cookies("userInfo")
aCookie.Values.Remove(subkeyName)
aCookie.Expires = DateTime.Now.AddDays(1)
Response.Cookies.Add(aCookie)

  Cookie 與安全性

  在使用 Cookie 時(shí),您必須意識(shí)到其固有的安全弱點(diǎn)。我所指的安全性并不是隱私問(wèn)題,正如我在前面的什么是 Cookie?中所述,隱私在更大程度上是某些用戶面對(duì)的問(wèn)題:這些用戶很關(guān)心 Cookie 中的信息是如何被使用的。而 Cookie 的安全性問(wèn)題與從客戶機(jī)獲取數(shù)據(jù)的安全性問(wèn)題類(lèi)似。對(duì)于初學(xué)者,就應(yīng)用程序而言,Cookie 是用戶輸入的另一種形式,因而很容易被他人非法獲取和利用。由于 Cookie 保存在用戶自己的計(jì)算機(jī)上,所以用戶至少可以看到您保存在 Cookie 中的信息。如果用戶愿意,還能在瀏覽器向您發(fā)送 Cookie 之前修改該 Cookie。

  所以,您千萬(wàn)不要在 Cookie 中保存保密信息 - 用戶名、密碼、信用卡號(hào)等等。在 Cookie 中不要保存不應(yīng)該由用戶掌握的內(nèi)容,也不要保存可能被其他竊取 Cookie 的人控制的內(nèi)容。

  同樣,要對(duì)從 Cookie 中得到的任何信息都持懷疑態(tài)度。不要認(rèn)為得到的數(shù)據(jù)就是您當(dāng)初設(shè)想的信息。處理 Cookie 值時(shí)采用的安全措施應(yīng)該與處理 Web 頁(yè)面中用戶鍵入的數(shù)據(jù)時(shí)采用的安全措施相同。例如,在頁(yè)面中顯示值之前,我會(huì)對(duì) Cookie 中的內(nèi)容進(jìn)行 HTML 編碼。這是一種標(biāo)準(zhǔn)的方法,可以在顯示之前凈化從用戶處得到的信息,對(duì) Cookie 的處理與此相同。

  另一個(gè)需要關(guān)心的問(wèn)題是,Cookie 是以純文本的形式在瀏覽器和服務(wù)器之間傳送的,任何可以截取 Web 通信的人都可以讀取 Cookie。您可以對(duì) Cookie 的屬性進(jìn)行設(shè)置,使其只能在使用安全套接字層(SSL,又稱 https://)的連接上傳輸。SSL 并不能防止保存在用戶計(jì)算機(jī)上的 Cookie 被他人讀取或操作,但它能防止 Cookie 在傳輸途中被他人截取。本文不討論 SSL,但您必須清楚,您可以對(duì) Cookie 進(jìn)行傳輸保護(hù)。有關(guān) SSL 的詳細(xì)信息,請(qǐng)參閱 Secure Sockets Layer: Protect Your E-Commerce Web Site with SSL and Digital Certificates(英文)。

  面對(duì)這些安全問(wèn)題,如何才能安全地使用 Cookie?您可以在 Cookie 中保存一些不重要的數(shù)據(jù),如用戶首選項(xiàng)或其他對(duì)應(yīng)用程序沒(méi)有重大影響的信息。如果確實(shí)需要把某些敏感信息(如用戶 ID)保存在 Cookie 中,就對(duì)這些信息進(jìn)行加密。一種可行的方法是利用 ASP.NET Forms Authentication 實(shí)用程序創(chuàng)建一個(gè)身份驗(yàn)證票據(jù),作為 Cookie 保存。本文不討論有關(guān)加密的問(wèn)題,但是,如果您需要在 Cookie 中保存敏感信息,就應(yīng)該試著采取措施來(lái)隱藏信息,防止被他人盜用。

  在 Mitigating Cross-site Scripting With HTTP-only Cookies(英文)一文中,您可以了解到更多有關(guān) Cookie 及其安全弱點(diǎn)的信息。

  檢查瀏覽器是否接受 Cookie

  我在前面的 Cookie 的限制一節(jié)中曾經(jīng)提到一個(gè)潛在問(wèn)題,即用戶可以設(shè)置自己的瀏覽器拒絕接受 Cookie。如何才能知道您是否可以讀寫(xiě) Cookie?在不能寫(xiě)入 Cookie 時(shí)不會(huì)出現(xiàn)任何錯(cuò)誤(例如 Response.Cookies 不會(huì)拋出異常),因?yàn)榉⻊?wù)器并不跟蹤呈現(xiàn)頁(yè)面后出現(xiàn)的情況。瀏覽器同樣不會(huì)向服務(wù)器發(fā)送任何有關(guān)其當(dāng)前的 Cookie 設(shè)置的信息。(也許您需要了解,但 HttpBrowserCapabilities.Cookies Property [英文] 屬性并不會(huì)告訴您 Cookie 是否被啟用,而只能告訴您當(dāng)前的瀏覽器是否支持 Cookie。)

  一種確定瀏覽器是否接受 Cookie 的方法是先編寫(xiě)一個(gè) Cookie,然后再嘗試讀取這個(gè) Cookie。如果不能讀取這個(gè) Cookie,則可以認(rèn)為該瀏覽器不接受 Cookie。

  我編寫(xiě)了一個(gè)簡(jiǎn)單的示例來(lái)說(shuō)明如何測(cè)試 Cookie 是否被接受。該示例包含兩個(gè)頁(yè)面。在第一個(gè)頁(yè)面中,我編寫(xiě)了一個(gè) Cookie,然后把瀏覽器重新定向到第二個(gè)頁(yè)面。第二個(gè)頁(yè)面嘗試讀取這個(gè) Cookie,轉(zhuǎn)而將瀏覽器重新定向到第一個(gè)頁(yè)面,并向 URL 添加一個(gè)帶有測(cè)試結(jié)果的查詢字符串變量。

  第一個(gè)頁(yè)面的代碼如下:

Sub Page_Load()
If Not Page.IsPostBack Then
 If Request.QueryString("AcceptsCookies") Is Nothing Then
  Response.Cookies("TestCookie").Value = "ok"
  Response.Cookies("TestCookie").Expires = DateTime.Now.AddMinutes(1)
  Response.Redirect("TestForCookies.aspx?redirect="Server.UrlEncode(Request.Url.ToString))
 Else
  labelAcceptsCookies.Text = "接受 Cookie = "Request.QueryString("AcceptsCookies")
 End If
End If
End Sub

  第一個(gè)頁(yè)面測(cè)試是否有回信,如果沒(méi)有,就搜索包含測(cè)試結(jié)果的查詢字符串變量 (AcceptsCookies)。如果沒(méi)有找到查詢字符串變量,則表示測(cè)試還沒(méi)有完成,代碼就寫(xiě)出一個(gè)名為“TestCookie”的 Cookie。寫(xiě)出 Cookie 之后,示例調(diào)用 Response.Redirect 來(lái)切換到測(cè)試頁(yè)面 (TestForCookies.aspx)。附加到測(cè)試頁(yè)面的 URL 的是名為 redirect 的查詢字符串變量,該變量中包含了當(dāng)前頁(yè)面的 URL,這樣就能在執(zhí)行測(cè)試后把重定向到該頁(yè)面。

  測(cè)試頁(yè)面可以完全由代碼組成,不需要包含控件。以下就是我使用的代碼:

Sub Page_Load()
 Dim redirect As String = Request.QueryString("redirect")
 Dim acceptsCookies As String
 ' 是否接受 Cookie?
 If Request.Cookies("TestCookie") Is Nothing Then
  ' 沒(méi)有 Cookie,因此不需要接受
  acceptsCookies = 0
 Else
  acceptsCookies = 1
  ' 刪除測(cè)試 Cookie
  Response.Cookies("TestCookie").Expires =DateTime.Now.AddDays(-1)
 End If
 Response.Redirect(redirect & "?AcceptsCookies=" & acceptsCookies,True)
End Sub

  讀取 redirect 查詢字符串變量后,代碼就嘗試讀取 Cookie。為了實(shí)現(xiàn)日常管理,如果該 Cookie 確實(shí)存在,就會(huì)被立即刪除。測(cè)試完成后,代碼從 redirect 查詢字符串變量傳遞的 URL 構(gòu)造一個(gè)新的 URL。新的 URL 也包括一個(gè)包含測(cè)試結(jié)果的查詢字符串變量。最后一步是使用新的 URL 將瀏覽器重定向到原來(lái)的頁(yè)面。

  這個(gè)示例十分簡(jiǎn)單,但說(shuō)明了通過(guò)運(yùn)行程序并查看結(jié)果來(lái)進(jìn)行測(cè)試的基本原則。其中最需要改進(jìn)的地方是要永久保存 Cookie 測(cè)試結(jié)果,這樣用戶就不必在每次瀏覽原始頁(yè)面時(shí)都重復(fù)進(jìn)行測(cè)試。但是,實(shí)際上并不能做到這一點(diǎn)。Cookie 不會(huì)起作用,原因是顯而易見(jiàn)的。另一種可能是把測(cè)試結(jié)果保存在會(huì)話狀態(tài)中,但在默認(rèn)情況下,會(huì)話狀態(tài)也依賴于 Cookie,而如果瀏覽器不接受 Cookie,會(huì)話狀態(tài)也不會(huì)起作用。解決后一個(gè)問(wèn)題的辦法是采用無(wú) Cookie 的會(huì)話狀態(tài)。下一節(jié)我將簡(jiǎn)要介紹會(huì)話狀態(tài)如何與 Cookie 協(xié)作。

  Cookie 和會(huì)話狀態(tài)

  當(dāng)用戶訪問(wèn)您的站點(diǎn)時(shí),服務(wù)器會(huì)為該用戶創(chuàng)建唯一的會(huì)話,會(huì)話將一直延續(xù)到用戶訪問(wèn)結(jié)束。對(duì)于每個(gè)會(huì)話,ASP.NET 都維護(hù)一種基于服務(wù)器的結(jié)構(gòu)(會(huì)話狀態(tài)),在該結(jié)構(gòu)中應(yīng)用程序可以保存用戶的相關(guān)信息。有關(guān)詳細(xì)信息,請(qǐng)參閱 Session State(英文)。

  ASP.NET 需要能跟蹤每個(gè)用戶的會(huì)話 ID,這樣才能把用戶映射到服務(wù)器上的會(huì)話狀態(tài)信息。默認(rèn)情況下,ASP.NET 使用一個(gè)非永久性的 Cookie 來(lái)保存會(huì)話狀態(tài)。如果您使用讀取 Cookie 一節(jié)的“讀取 Cookie 集合”中的示例,您可能就會(huì)在 Cookie 中發(fā)現(xiàn)一個(gè)會(huì)話狀態(tài) Cookie。

  但是如果用戶禁用了瀏覽器的 Cookie,會(huì)話狀態(tài)就不能使用 Cookie 來(lái)保存會(huì)話 ID,會(huì)話狀態(tài)也不會(huì)起作用。這就是為什么我在前面的檢查瀏覽器是否接受 Cookie 中說(shuō),無(wú)法在 Cookie 測(cè)試完畢后把測(cè)試結(jié)果實(shí)際保存在會(huì)話狀態(tài)中,因?yàn)闆](méi)有 Cookie 就沒(méi)有會(huì)話狀態(tài)。

  ASP.NET 提供了一種解決方案,即利用無(wú) Cookie 的會(huì)話。您可以配置自己的應(yīng)用程序,不在 Cookie 中保存會(huì)話 ID,而是在站點(diǎn)頁(yè)面的 URL 中保存。會(huì)話 ID 保存在 URL 中,也就是 ASP.NET 將 ID 保存在瀏覽器中,從而能夠在用戶請(qǐng)求其他頁(yè)面時(shí)取回 ID。

  無(wú) Cookie 會(huì)話可以避免瀏覽器拒絕 Cookie 的問(wèn)題,使您能夠使用會(huì)話狀態(tài)。如果您的應(yīng)用程序依賴于會(huì)話狀態(tài),您可能就需要對(duì)其進(jìn)行配置,使它能使用無(wú) Cookie 會(huì)話。但是,在某些情況下,如果用戶與其他人共享 URL - 可能是用戶通過(guò)電子郵件將 URL 發(fā)送給同事,而該用戶的會(huì)話仍然處于激活狀態(tài) - 那么最終這兩個(gè)用戶可能共享同一個(gè)會(huì)話,結(jié)果將難以預(yù)料。

關(guān)鍵詞:ASP.NETCookie

贊助商鏈接: