聊Cookie
1. Cookie是怎么出現(xiàn)的傻铣?
- 可由服務(wù)端設(shè)置,也可由客戶端設(shè)置漆枚,如果兩端都沒有設(shè)置則不存在Cookie
- 來源于客戶端設(shè)置竞川,即通過
document.cookie = 'xxx=yyy'
的形式 - 來源于服務(wù)端設(shè)置,操作如下:
- 瀏覽器發(fā)送HTTP請(qǐng)求
- 服務(wù)器收到請(qǐng)求酒唉,設(shè)置Cookie并在響應(yīng)頭添加
Set-Cookie
字段 - 瀏覽器收到響應(yīng)后保存Cookie
- 下次請(qǐng)求該服務(wù)器都通過
Cookie
字段將Cookie發(fā)送給服務(wù)器
2. Cookie格式
Cookie以鍵值對(duì)形式的字符串保存矩桂,即key=value
,例如name=cookie_name
黔州。除了Name/Value外耍鬓,Cookie字符串值中還存在許多特殊的key值,具體如下:
- Path:指定一個(gè)URL路徑流妻,如果沒有定義則使用當(dāng)前文檔位置的路徑牲蜀。如果設(shè)置了
path=/docs
,那么/test
路徑下不會(huì)攜帶Cookie首部绅这,/docs/test
則會(huì)攜帶 - Domain:指定可以送達(dá)的域名涣达,如果沒有指定,默認(rèn)為當(dāng)前文檔位置的路徑的域名部分。這里要注意的是度苔,不能跨域設(shè)置Cookie匆篓,如果在
a.com
下設(shè)置此屬性為b.com
是無效的。Domain
與Path
一起為Cookie指定作用域寇窑,即在哪些URL下是有效的鸦概。 - Expires:用于設(shè)置Cookie的過期時(shí)間,默認(rèn)值為
Session
甩骏,表示為會(huì)話性Cookie窗市。 - Max-Age:設(shè)置到失效的時(shí)長(zhǎng),有三種情況如下饮笛。當(dāng)與Expires屬性并存咨察,優(yōu)先級(jí)高于Expires
- 正數(shù):持久化緩存直到過期
- 負(fù)數(shù):會(huì)話性Cookie
- 0:立即刪除
- Secure:表示Cookie只通過https協(xié)議傳輸。
- HTTPOnly:增刪改查只由服務(wù)端操作福青,客戶端腳本不得操作摄狱。
- SameSite:可以讓 Cookie 在跨站請(qǐng)求時(shí)不會(huì)被發(fā)送,從而可以阻止跨站請(qǐng)求偽造攻擊(CSRF)无午。最近很熱門媒役, 因?yàn)镃hrome80 版本中默認(rèn)屏蔽了第三方的 Cookie。包含以下可選的三個(gè)值:
- Strict:僅發(fā)送與當(dāng)前URL相同站點(diǎn)的Cookie
- Lax:允許部分第三方請(qǐng)求攜帶Cookie
- None:無論是否跨站都會(huì)攜帶Cookie
3. 操作Cookie如何清除Cookie
操作時(shí)需要注意的是宪迟,要將值轉(zhuǎn)換為字符串刊愚,最好通過encodeURIComponent
。另外賦值Cookie時(shí)踩验,每一次都是一條新的記錄(key值相同會(huì)覆蓋)鸥诽。
// 瀏覽器設(shè)置
document.cookie = 'name=cookie';
document.cookie; //name=cookie
//再次設(shè)置時(shí),值會(huì)追加在后面
document.cookie = 'age=18';
document.cookie; //name=cookie; age=18
//相同key值的設(shè)置
document.cookie = 'name=cookie_again';
document.cookie; //name=document.cookie; age=18
//一次寫入多個(gè)key/value
document.cookie = 'name=cookie;age=18'
document.cookie //name=cookie箕憾,并不支持一次寫入多個(gè)
//設(shè)置特殊屬性
document.cookie = 'name=cookie;max-age=60000'; //成功
//單獨(dú)設(shè)置特殊屬性
document.cookie = 'max-age=6000';
document.cookie; //max-age=6000牡借,單獨(dú)設(shè)置會(huì)轉(zhuǎn)化為key/value
4. Cookie的類別?
Cookie根據(jù)作用不同袭异,分為以下兩類:
-
會(huì)話性Cookie:當(dāng)
Expires/Max-Age
屬性缺省時(shí)钠龙,表現(xiàn)為會(huì)話性。此時(shí)值保存在客戶端內(nèi)存中御铃,當(dāng)關(guān)閉瀏覽器時(shí)失效碴里。值得注意的是,有些瀏覽器會(huì)有會(huì)話恢復(fù)功能上真,這種情況下就算關(guān)閉瀏覽器咬腋,會(huì)話Cookie依然會(huì)被保留下來。 - 持久性Cookie:持久性Cookie與會(huì)話性不同睡互,會(huì)保存在硬盤中根竿,直至過期或被清除陵像。持久性Cookie一般是客戶端用來緩存用戶數(shù)據(jù)。
5. Cookie有什么特點(diǎn)/限制寇壳?
- 管理會(huì)話狀態(tài)
- 瀏覽器行為跟蹤
- 最大容量4kb
- 每次請(qǐng)求時(shí)會(huì)附帶在頭部發(fā)送給服務(wù)器醒颖,會(huì)增加請(qǐng)求的大小
- 安全問題,好吧壳炎,存在瀏覽器的都不怎么安全
聊Storage
- 有l(wèi)ocalStorage與sessionStorage兩種泞歉,區(qū)別在于sessionStorage是會(huì)話性緩存,在當(dāng)前標(biāo)簽頁關(guān)閉(或?yàn)g覽器關(guān)閉)后會(huì)被清除匿辩。而localStorage是持久性緩存疏日,只要不手動(dòng)清除可一直保留。
- 限制
-
大腥龊骸:一般瀏覽器為5M左右,網(wǎng)上有一部分資料說微信等瀏覽器只有2.5M涕滋,于是用http://dev-test.nemikor.com/web-storage/support-test/這個(gè)網(wǎng)站測(cè)試了一下微信webview睬辐,顯示的依然是5M左右。問題來了宾肺,如果超出使用大小限制會(huì)如何溯饵?答案是會(huì)拋出錯(cuò)誤
QUOTA_EXCEEDED_ERR
跨域:瀏覽器同源策略,只可以訪問同源下的Storage锨用,而sessionStorage在此基礎(chǔ)上更進(jìn)一步丰刊,只能訪問同一標(biāo)簽頁中的Storage,同一頁面內(nèi)嵌的同源iframe的Storage也可以訪問增拥。
是否可用:目前的兼容性是很好的啄巧,但有些情況需要一定的手段去檢測(cè)是否可用,比如在隱身/無痕模式下的safari掌栅,存在localStorage對(duì)象秩仆,但無進(jìn)行setItem操作。
-
選擇使用哪種
成熟的人不做選擇猾封,成熟的人都想要??澄耍。在項(xiàng)目中應(yīng)當(dāng)結(jié)合實(shí)際的需求進(jìn)行取舍,比如:
- 需要兼容到極低版本的瀏覽器(懂的都懂)晌缘,那么肯定使用Cookie了
- 少量的用戶狀態(tài)數(shù)據(jù)齐莲,且有會(huì)話性Cookie需求,Cookie會(huì)更好
- 大容量的存取磷箕,選Storage
- 需要持久化緩存选酗,localStorage吧
- 只需要在當(dāng)前頁面使用的數(shù)據(jù),sessionStorage搞一個(gè)
- ……
localStorage如何實(shí)現(xiàn)與Cookie一樣的過期功能
localStorage本身并沒有緩存過期的實(shí)現(xiàn)岳枷,所以有需要的話開發(fā)人員自己去擴(kuò)展星掰。思路也很簡(jiǎn)單多望,在設(shè)置緩存時(shí)傳入過期時(shí)間,以及記錄設(shè)置時(shí)的初始時(shí)間戳氢烘,這樣在獲取緩存時(shí)即可通過對(duì)比當(dāng)前時(shí)間查看是否已過期怀偷,簡(jiǎn)單的實(shí)現(xiàn)如下:
const $local = {
/**
* 設(shè)置緩存
* @param {string} key
* @param {*} value
* @param {number} expires 多少毫秒后過期
*/
set: (key, value, expires) => {
localStorage.setItem(key, JSON.stringify({
value: value,
expires: expires,
startTime: Date.now() //緩存設(shè)置時(shí)間
}))
},
/**
* 獲取緩存
* @param {string} key
*/
get: key => {
let cache = localStorage.getItem(key);
//無緩存值
if (!cache) {
return undefined
}
let {expires, startTime, value} = JSON.parse(cache);
//已過期
if (expires && Date.now() - startTime > expires) {
return undefined
}
return value
}
}
如何確定是否localStorage是否可用呢?
以下是大致的思想播玖,當(dāng)然在項(xiàng)目中會(huì)把用成熟的庫來進(jìn)行操作椎工,推薦store.js
等庫。
//檢測(cè)是否存在localStorage
if ('localStorage' in window) {
try {
//可用
localStorage.setItem('incognito.test', '1');
} catch (error) {
//不可用
}
} else {
//不可用
}
同源多頁面通訊
這也是一個(gè)比較常見的問題蜀踏,實(shí)現(xiàn)的方法有很多维蒙,其中就包括使用StorageEvent
來實(shí)現(xiàn)。什么是StorageEvent
呢果覆?其實(shí)就是一個(gè)事件颅痊,當(dāng)Storage被設(shè)置時(shí)會(huì)觸發(fā),注意點(diǎn)如下局待。利用這個(gè)事件即可實(shí)現(xiàn)同源多頁面通訊
- 當(dāng)前頁面Storage改變不會(huì)觸發(fā)此事件斑响,非當(dāng)前頁(同源)會(huì)收到此事件。實(shí)現(xiàn)如下
window.addEventListener('storage', function (e) { //在此進(jìn)行操作 });
- 設(shè)置的key值沒有改變也不會(huì)觸發(fā)此事件
//第一次觸發(fā)事件 window.localStorage.setItem('test', '123'); //值沒有改變钳榨,第二次不觸發(fā) window.localStorage.setItem('test', '123');
結(jié)語??
回顧了下Cookie與Storage舰罚,有部分是之前沒有注意到的,比如突破Storage存儲(chǔ)限制后會(huì)拋出錯(cuò)誤薛耻;在使用localStorage营罢,并以持久化存儲(chǔ)為目標(biāo)時(shí)并不絕對(duì)可靠,例如在手機(jī)瀏覽器/webview中饼齿,系統(tǒng)內(nèi)存不足時(shí)會(huì)自動(dòng)清理緩存文件饲漾,這些都是平時(shí)沒有注意到的地方。
部分內(nèi)容來自以下blog