隨着 Web 應用程序的出現,也產生了對於能夠直接在客戶端上存儲用戶信息能力的要求。想法很合乎邏輯,屬於某個特定用戶的信息應該存在該用戶的機器上。無論是登錄信息、偏好設定或其他數據,web應用提供者發現他們在找各種方式將數據存在客戶端上。這個問題的第一個方案是以 cookie 的形式出現的,cookie 是過去 Netscape Communications 公司創造的,並在一個標題爲 "持久客戶端狀態 -- HTTP Cookies" 的標準中被闡述。今天,cookie 只是在客戶端存儲數據的其中一種選項。
19.1 cookie
HTTP Cookie ,通常直接叫做 cookie ,最初是在客戶端用於存儲會話信息的。該標準要求服務器對任意 HTTP 請求發送 Set-Cookie HTTP 頭作爲響應的一部分,其中包含會話信息。例如,這種服務器響應的頭可能如下:
這個 HTTP 響應設置以 name 爲名稱、以 value 爲值的一個 cookie ,名稱和值在傳送時都必須是 URL 編碼的。瀏覽器會存儲這樣的會話信息,並在這之後,通過爲每個請求添加 Cookie HTTP 頭將信息發送回服務器,如下所示:
發送回服務器的額外信息可以用於唯一驗證客戶來自於發送的哪個請求。
19.1.1 限制
cookie 在性質上是綁定在特定的域名下的。當設定了一個 cookie 後,再給創建它的域名發送請求時,都會包含這個 cookie 。這個限制確保了存儲在 cookie 中的信息只能讓批准的接受者訪問,而無法被其他域訪問。
由於 cookie 是存在客戶端計算機上的,還加入了一些限制確保 cookie 不會被惡意使用,同時不會佔據太多磁盤空間。每個域的 cookie 總數是有限的,不過瀏覽器之間各有不同。如下所示。
- IE6 以及更低版本限制每個域名最多 20 個 cookie。
- IE7 和之後版本每個域名最多 50 個。IE7 最初是支持每個域名最大 20 個 cookie ,之後被微軟的一個補丁所更新。
- Firefox 限制每個域最多 50 個 cookie 。
- Opera 限制每個域最多 30 個 cookie 。
- Safari 和 Chrome 對於每個域的 cookie 數量限制沒有硬性規定。
19.1.2 cookie 的成分
- 名稱 -- 一個唯一確定 cookie 的名稱。cookie 名稱是大小寫不敏感的,所以 myCookie 和 MyCookie 被認爲是同一個 cookie。然而,實踐中最好將 cookie 名稱看作是大小寫敏感的,因爲某些服務器會這樣處理 cookie 。cookie 的名稱必須是經過 URL 編碼的。
- 值 -- 存儲在 cookie 中的字符串值。值必須被 URL 編碼。
- 域 -- cookie 對於哪個域是有效的。所有向該域發送的請求中都會包含這個 cookie 信息。這個值可以包含子域 (subdomain,如 www.wrox.com) ,也可以不包含它 (如 .wrox.com,則對於 wrox.com 的所有子域都有效)。如果沒有明確設定,那麼這個域會被認作來自設置 cookie 的那個域。
- 路徑 -- 對於指定域中的那個路徑,應該向服務器發送 cookie 。例如,你可以指定 cookie 只有從 http://www.wrox.com/books/ 中才能訪問,那麼 http://www.wrox.com 的頁面就不會發送 cookie 信息,即使請求都是來自同一個域的。
- 失效時間 -- 表示 cookie 何時應該被刪除的時間戳 (也就是,何時應該停止向服務器發送這個 cookie)。默認情況下,瀏覽器會話結束時即將所有 cookie 刪除;不過也可以自己設置刪除時間。這個值是個 GMT 格式的日期 (Wdy, DD-Mon-YYYY HH:MM:SS GMT), 用於指定應該刪除 cookie 的準確時間。因此,cookie 可在瀏覽器關閉後依然保存在用戶的機器上。如果你設置的失效日期是個以前的時間,則 cookie 被立刻刪除。
- 安全標誌 -- 指定後,cookie 只有在使用 SSL 連接的時候才發送到服務器。例如,cookie 信息只能發送給 https://www.wrox.com,而 http://www.wrox.com 的請求則不能發送 cookie。
19.1.3 JavaScript 中的 cookie
var CookieUtil = {
get: function(name){
var cookieName = encodeURIComponent(name) + "=",
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if(cookieStart > -1){
var cookieEnd = document.cookie.indexOf(";", cookieStart);
if(cookieEnd == -1){
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
},
set: function(name, value, expires, path, domain, secure){
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if(expires instanceof Date){
cookieText += "; expires=" + expires.toGMTString();
}
if(path){
cookieText += "; path=" + path;
}
if(domain){
cookieText += "; domain=" + domain;
}
if(secure){
cookieText += "; secure";
}
document.cookie = cookieText;
},
unset: function(name, path, domain, secure){
this.set(name, "", new Date(0), path, domain, secure);
}
};
// 設置 cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");
// 讀值
alert(CookieUtil.get("name")); // "Nicholas"
alert(CookieUtil.get("book")); // "Professional JavaScript"
// 刪除 cookie
CookieUtil.unset("name");
CookieUtil.unset("book");