cookie最初是設計給服務端用的。若是客戶端有cookie,則每次請求都會發給服務端。下面來具體看一下這個機制。node
就像上面說的,cookie最初是設計給服務端使用的。cookie就像服務端給這個客戶端加的一個標籤,當客戶端再次請求時,會帶着這個標籤,那麼服務器就能經過攜帶的cookie知道當前的客戶端是誰了。api
cookie的設置過程大致以下:跨域
Cookie主要用於如下三個方面:數組
會話狀態管理(如用戶登陸狀態、購物車、遊戲分數或其它須要記錄的信息)瀏覽器
個性化設置(如用戶自定義設置、主題等)緩存
瀏覽器行爲跟蹤(如跟蹤分析用戶行爲等)安全
cookie 是能夠被修改的,客戶端和服務端均可以對已經設置的cookie進行修改。服務器
在1.1部分的cookie設置過程當中可知,若是客戶端將原本是 Joey的 cookie 改爲 Ross,那麼服務器就會認爲如今發請求的客戶端是 Ross,可能會給客戶端 Joey 返回原本屬於 Ross 的內容。這確定是不該該的。cookie
因此說, cookie 是不可信的。網絡
客戶端在得到服務端返回的 cookie 後,在之後再給服務器發請求時,不管服務端是否是想要 cookie, 都會放在請求裏發過去。
咱們知道,網絡請求是很是耗時間的,若是cookie過大,每次請求服務器時都會在 header 中帶上 cookie ,則網絡請求時間會過長。
因此大多數瀏覽器都對每一個域的cookie數量和大小有限制,每一個瀏覽器對cookie數量的限制不相同,但對總大小的限制大都是4096B。
若是新加入的cookie要超過了瀏覽器的最大數量限制,會刪除較早的 cookie 以騰出空間。不一樣瀏覽器的刪除策略不一樣,有的會刪除最近最少使用的 cookie,例如 IE和Opera;有些彷佛會隨機選擇一個來刪除,例如 Firefox...
若是新的加入新的 cookie 以後全部 cookie 的總大小超過限制,則新的 cookie 不會設置成功, 會被丟棄。
因此,不要設置太多 cookie, 以避免出現意料不到的事情。
cookie由如下幾個字段組成:
name
:名稱,惟一值,用來惟一識別cookie,不分大小寫。必須通過 URL 編碼value
:值,對應於名稱,必須通過 URL 編碼domain
:域,設置cookie對於哪一個域是有效的,都向這個域裏發cookie。例如domain值爲www.baidu.com,則全部發向這個網址的請求,都會發這個cookiepath
:路徑,指定域裏的路徑能夠接受這個cookie,例如百度下的/search路徑:www.baidu.com/searchexpires
:過時時間,表示這個cookie何時應該被刪除,這是個日期格式的。若是沒有定義,cookie會在對話結束時過時。若是想讓一個cookie立刻過時,則能夠將這個值設置成過去的時間。max-age
:過時倒計時,以秒爲單位。若是設置成0,則這個cookie馬上失效,設置負數時不會產生cookie文件secure
:設置該 cookie 只經過https協議傳輸,這不是鍵值對,是個標記,寫上就表明設置爲只在使用 https 傳輸。從 Chrome 52 和 Firefox 52 開始,不安全的站點使用http協議的站點沒法使用Cookie的 Secure
標記http-only
:設置不容許在瀏覽器端用 JavaScript 獲取到 cookie。這也不是個鍵值對,是個標記,寫上就表明生效。能夠用來防止跨域腳本(XSS )攻擊samesite
:要求cookie在跨站請求時不會被髮送,防止跨站請求僞造(CSRF)的特性,可取值其中除name: value
爲必須以外,其他都是可選項。
在客戶端使用 JavaScript 對 cookie 的操做能夠分爲兩類,分別是讀取 cookie 和 設置 cookie,下面分別進行討論。
BOM 的提供的操做 cookie 的 api 看起來有些難用。
使用 document.cookie 便可得到該頁面中全部的 cookie,例如,咱們來看看百度學術給我設置了什麼cookie。打開http://xueshu.baidu.com/。按F12,打開上部分的 Application 選項卡,而後打開左側的 cookies。
百度學術在個人電腦裏保存的cookie如圖:
而後在命令臺上經過 document.cookie 來獲取頁面裏的 cookie:
// 獲取 cookie, 獲得的是全部 cookie 組成的字符串
let cookies = document.cookie;
// 提取出全部的 cookie 到數組中
let cookieArray = cookies.split(';');
// 用 console.table 輸出cookie數組,這樣比較清晰
console.table(cookieArray);
複製代碼
結果以下:
能夠看到經過 document.cookie 獲取的 cookie 的 name 和 value 與瀏覽器工具獲得的相同。
以圖中第一個cookie爲例,cookie 名爲 PSTM , value 是1563885xxx,域名是 .baidu.com,過時時間是2087年8月10號,其餘屬性都取默認值。
給 document.cookie 賦一個新的 cookie 字符串能夠設置一個新的 cookie 了。
以MDN爲例,在這個網站域名下設置一個本身的cookie,配置以下:
其餘選項不設置,也就是取默認值。
設置以前的 cookie 爲:
設置:
let name = 'username',
value = 'test',
domain = '.mozilla.org',
path = '/';
var myCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';domain=' + domain + ';path=' + path;
document.cookie = myCookie;
複製代碼
結果以下:
能夠看到 cookie 設置成功了。
因爲不一樣服務端程序的在響應報文的頭部設置 set-cookie 操做的具體代碼不一樣,這裏以 node.js 的 koa 框架爲例。
先起一個極簡的 server,而後對於訪問者返回的報文的 header 都設置 set-cookie 頭部:
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.cookies.set('koa_cookie_name', 'koa_cookie_value');
ctx.body = 'cookie setted';
});
app.listen(3001, (e) => {
console.log('server listening port 3001');
});
複製代碼
進入'http://localhost:3001/'後去查看 cookie:
能夠看到服務端傳來的 cookie。
sessionStorage 和 localStorage 有與cookie不一樣的兩點:
sessionStorage 和 localStorage 都是 Storage 對象;都是以名值對的形式存儲數據,存儲數據的key和value都是字符串(string)類型,若是傳入的不是字符串類型,會被轉換爲字符串類型。
因此,若是想把非字符串類型的數據存進來,要預先手動進行編碼,取出來後要再進行解碼。
這兩類對象有着相同的增刪改查數據的 api,因此能夠用其中的一個對象爲例子,來演示這些 api,這裏選擇 sessionStorage :
setItem(key, value)
:將一個鍵值對的保存,若是兩次保存的key相同可是value不一樣,則後面的覆蓋前面的。getItem(key)
:獲取指定 key 對應的 valueremoveItem(key)
:刪除指定的 key 及其 valuekey(index)
:獲取指定位置的...clear()
:刪除全部數據還有一個屬性:
length
屬性:判斷存了多少名值對,上面key(index)
方法中的參數 index 的範圍是 0 =< index <= length - 1使用sessionStorage來演示上面的 api:
存入兩個鍵值對,使用
setItem(key, value)
方法:
sessionStorage.setItem('key 1', 'value 1');
sessionStorage.setItem('key 2', 'value 2');
複製代碼
打開瀏覽器頁面的開發者工具,點擊Application選項卡,點擊左側的 session Storage,就能看到兩條剛剛保存的鍵值對了。
獲取兩個鍵對應的數據,使用
getItem(key)
方法:
let value1 = sessionStorage.getItem('key 1');
let value2 = sessionStorage.getItem('key 2');
console.log(value1, value2); // value 1 value 2
複製代碼
刪除
'key 1'
和其對應的數據,使用removeItem(key)
方法:
sessionStorage.removeItem('key 1');
複製代碼
從圖中能夠看到存儲的數據只剩下 key 2: value 2 了。
如今再添加幾條數據:
sessionStorage.setItem('key 3', 'value 3');
sessionStorage.setItem('key 4', 'value 4');
sessionStorage.setItem('key 5', 'value 5');
sessionStorage.setItem('key 6', 'value 6');
複製代碼
獲得:
輸出如今存儲的數據條數,也就是鍵值對的條數,並輸出最後一條,使用
length
屬性:
let key_value_count = sessionStorage.length;
console.log('如今存儲了 ' + key_value_count + ' 條數據'); // 如今存儲了 5 條數據
複製代碼
一次性刪除全部數據,使用
clear()
方法:
sessionStorage.clear();
複製代碼
結果:
因爲 Storage 自己就是對象,因此也可使用通常對象的讀取與設置屬性的語法來存取對象,本質就是經過設置屬性和值的鍵值對來添加與讀取數據。
存取的方式也和普通對象同樣有兩種,分別是點號法和中括號語法,例以下面的例子:
sessionStorage.key1 = 'value 1';
console.log(sessionStorage.key1);
sessionStorage['key 2'] = 'value 2';
console.log(sessionStorage['key 2']);
複製代碼
結果如圖:
這種語法和 api 中的 setItem
和getItem
效果相同。
想刪除一個數據時,可使用 delete
關鍵字,和刪除普通對象屬性的操做相同:
delete sessionStorage.key1;
delete sessionStorage['key 2'];
複製代碼
結果:
這和 removeItem
的效果相同。
sessionStorage 和 localStorage 的區別在聲明週期和做用域這兩點上,具體來講以下。
在 Storage 裏的數據被添加、修改、刪除時,會觸發 storage 事件,能夠在 window 對象上添加事件監聽程序 onstorage 來監聽事件,而且能夠獲取事件對象。
storage 事件對象上有以下幾個屬性:
注意:localStorage 的事件採用的是廣播機制,正在訪問相同站點的頁面都會受到信息。這樣能夠完成必定的標籤頁之間的通訊。
參考:
MDN
《JavaScript高級程序設計》
《JavaScript權威指南》