為何需要 cookie 和 session众辨?
首先來了解 HTTP (HyperText Transfer Protocol 超文本傳輸協(xié)議) 的幾個特性:
HTTP 建立于客戶端-服務端(client/server)模型之上比驻,瀏覽器發(fā)送請求钳枕,Web服務器接收請求后向客戶端發(fā)送響應信息
HTTP 是無狀態(tài)的(stateless)協(xié)議执解,每一次傳輸都是獨立的谬盐,互不影響寥粹。
HTTP 是一個應用層 (application layer) 協(xié)議劝枣,在傳輸層(transfer layer)協(xié)議之上,使用(TCP)作為傳輸層協(xié)議泥从。
客戶端請求服務端使用不同的請求方式(包括:GET句占、POST、DELETE躯嫉、PUT 等)纱烘。
HTTP 定義了服務端狀態(tài)碼返回給客戶端(如:200、404祈餐、500)擂啥。
HTTP 支持設置頭部 headers,(包括:Cache-Control帆阳、Content-type 等)哺壶。
http請求報文:
HTTP 是無狀態(tài)的,意味著每次頁面加載蜒谤、每次請求都是獨立的事件变骡,和前后的事件沒有關聯(lián)“攀牛客戶端請求服務之后塌碌,服務端不能區(qū)分發(fā)起 HTTP 請求的用戶以及用戶在網(wǎng)站的狀態(tài)等,Cookie 和 Session 使 HTTP 能夠維持狀態(tài)旬盯,讓網(wǎng)站能夠記住用戶的一些信息台妆。
Cookie & Session
Cookie 通常是由 瀏覽器 保存在用戶電腦的小文本文件,經(jīng)過瀏覽器轉換成包含用戶網(wǎng)站上的信息的文本胖翰,在瀏覽器發(fā)送 HTTP 請求的時候會把這些信息加在請求頭中發(fā)送給服務端接剩,服務端再根據(jù) Cookie 來判斷不同用戶的信息。
Session 是 服務端 存儲的用來標識用戶信息的數(shù)據(jù)萨咳,當用戶訪問網(wǎng)站時懊缺,服務器會為這個用戶創(chuàng)建一個唯一的 session id,服務器會把這個id通過 cookie 的形式傳給瀏覽器,瀏覽器接收 cookie 之后鹃两,請求就能攜帶這個 cookie 訪問服務器遗座,通過這個session id 服務端就能夠對訪問的用戶進行辨別。
舉個栗子:
商店發(fā)的會員卡(cookie)俊扳,它記錄了用戶的信息(identification)途蒋,并且是由商店(服務器)發(fā)給用戶(瀏覽器),每次用戶去商店消費都會攜帶著會員卡馋记,由于商店管理了自己發(fā)布的會員卡信息号坡,可以通過用戶會員卡ID(session id)找到該用戶的信息。
Session cookies 和 Persistent cookies
- 會話 cookie(Session cookies)在瀏覽網(wǎng)頁時被創(chuàng)建梯醒,通常放在活動內存宽堆,會話結束時(瀏覽器關閉)會被刪除。
- 持久化 cookie(Persistent cookies)瀏覽網(wǎng)頁是被創(chuàng)建茸习,并且沒有失效之前畜隶,始終存在于瀏覽器的 cookie 存儲目錄,在到達失效日期時會被刪除逮光。
Cookie 包含的內容
通常 cookie 都會包含以下內容:
- Cookie 來源的服務器名稱
- Cookie 保存的時間
- 隨機生成的唯一的數(shù)值
Cookie 是一個很小的文本文件,通常會被命名為類似 abc@example.com.txt 的文件墩划,如果打開這些文件涕刚,可以看到類似如下的內容:
HMP1 1 example.com/ 0 4058205869
384749284 403847430 3449083948 *
Google Chrome 瀏覽器使用 SQLite 文件存儲 cookie ,默認存儲在:
C:\Users\<your_username>\AppData\Local\Google\Chrome\User Data\Default\
并且 Cookie 的值被加密了乙帮,因此無法直接打開杜漠。
Cookie 相關
- 不設置 cookie 過期時間,cookie 會在會話結束后銷毀
- 持久 cookie 無法改成會話 cookie察净,除非刪除再重新創(chuàng)建 cookie
- 將 cookie 的
domain
選項設置為主域名驾茴,子域名可以攜帶該 cookie 的發(fā)送到服務器
如何使用 cookie?
服務端
服務器通過響應頭 Set-Cookie
來告訴瀏覽器創(chuàng)建一個 cookie氢卡,Set-Cookie
的值一個字符串锈至,其格式如下:
Set-Cookie: <name>=<value>[; expires=<date>][; domain=<domain>][; path=<path>][; secure][; httponly]
上面的格式中,”[]“ 內部都是可選值译秦,他們分別有如下作用:
-
<name>=<value>
- 儲存的字符串峡捡,會被瀏覽器攜帶發(fā)送回服務器筑悴,通常是一個name=value
格式的字符串 -
expires
- Cookie 的過期時間们拙,不設置的話,創(chuàng)建的 cookie 在會話結束后銷毀阁吝,格式為DD-Mon-YYYY HH:MM:SS GMT
-
domain
- Cookie 被設置的域砚婆,只有向該域發(fā)送 HTTP 請求時才會攜帶對應的 cookie -
path
- Cookie 被設置的路徑,之后向該路徑發(fā)起請求才會攜帶對應的 cookie -
secure
- 一個 boolean 標記 cookie 是否只能通過 HTTPS 請求發(fā)送至服務器突勇。 -
httponly
- 告訴瀏覽器該 cookie 不能通過 JavaScript 訪問装盯,可以阻止跨站腳本攻擊(XSS)竊用 cookie坷虑。
可以返回多個 Set-Cookie
頭來設置多個 cookie:
Set-Cookie: name=moyufed; path=/; expires=Mon, 26 Jul 2021 11:10:02 GMT; domain=localhost
Set-Cookie: name2=moyufed2; path=/; expires=Mon, 26 Jul 2021 11:10:02 GMT; domain=localhost
客戶端
JavaScript 通過 document.cookie
進行 cookie 的操作,但是僅限于非 httpOnly
的情況:
獲取 cookie:
document.cookie
創(chuàng)建或修改 cookie:
document.cookie="name="+username;
在瀏覽器發(fā)送請求時验夯,會將 cookie 添加到請求頭中猖吴,如果有多個 cookie,將以分號和空格分隔挥转,cookie 的格式如下:
Cookie: name=moyufed; name2=moyufed2
在 koa 中使用 cookie
Koa 已經(jīng)提供了從通過上下文(ctx
)直接讀寫入 cookie 的方法海蔽,分別為:
-
ctx.cookies.get(name, [options])
- 通過上下文讀取 cookie -
ctx.cookies.set(name, value, [options])
- 通過上下文寫入 cookie
ctx.cookies.set(
'name',
'moyufed',
{
domain: 'localhost', // 設置 cookie 的域
path: '/', // 設置 cookie 的路徑
maxAge: 24 * 60 * 60 * 1000, // cookie 的有效時間 ms
expires: new Date('2020-10-10'), // cookie 的失效日期,如果設置了 maxAge绑谣,expires 將沒有作用
httpOnly: false, // 是否要設置 httpOnly
overwrite: false // 是否要覆蓋已有的 cookie 設置
}
)
上面的代碼沒有設置 httpOnly党窜,通過 document.cookie
可以獲取到 "name=moyufed"
,在訪問 '/'
路徑時借宵,可以看到請求頭里面攜帶了設置的 cookie幌衣。事實上 koa2 使用了 npm 的 cookies 模塊來讀寫 cookie,上面的配置都可以從 cookies 源碼查看壤玫。
如何使用 session豁护?
Session 存儲在服務端,不會在網(wǎng)絡中進行傳輸欲间,但服務器產生的 session id 會以 cookie 存在客戶端楚里。
用戶通過瀏覽器訪問 web 站點,服務器會產生一個唯一的 session id猎贴,通過 Set-Cookie
響應頭將其發(fā)送到瀏覽器班缎,之后瀏覽器發(fā)送的請求都會自動攜帶這個 cookie,服務器根據(jù) cookie 獲取到的 session id 來獲得存儲在服務端的用戶的信息她渴。
用戶信息儲存的方式可以是內存(Redis)或數(shù)據(jù)庫达址。
在 koa 中使用 session
Koa2 沒有提供直接設置 session 的操作,但也有很多用于操作 session 的中間件趁耗,這里將使用 koa-session-minimal 中間件來處理 session沉唠,并且還將使用 redis 作為儲存介質。同樣苛败,也有 koa-redis 來為 koa 的 session 中間件提供 redis 儲存右冻。
關于 redis 的安裝可以查看 【前端開發(fā)日常 - 4】Windows安裝Redis及簡單使用 。
安裝中間件:
$ npm install koa-session-minimal koa-redis
示例代碼:
// app.js
const Koa = require('koa'); // 引入koa
const Router = require('koa-router');
const session = require('koa-session-minimal');
const redisStore = require('koa-redis');
const app = new Koa(); // 創(chuàng)建 koa 應用
const router = new Router(); // 使用 koa-router
// 存放 sessionId 的 cookie 配置著拭,根據(jù)情況自己設定
let cookie = {
maxAge: 60 * 60 * 1000, // cookie 有效時長(ms)
expires: '', // cookie 失效時間
path: '', // 寫 cookie 所在的路徑
domain: '', // 寫 cookie 所在的域名
httpOnly: true, // 是否只用于 http 請求中獲取
overwrite: true, // 是否允許重寫
secure: '',
sameSite: '',
signed: true,
}
app.use(session({
key: 'SESSION_ID', // 使用 SESSION_ID 來作為 redis key 的前綴
store: redisStore(),
cookie: cookie // 設置 session id 儲存的 cookie
}))
router.get('/', async ctx => {
ctx.body = 'Hello world!';
})
router.get('/get', async ctx => {
// 讀取和修改 session 信息
ctx.session.count = ctx.session.count + 1
ctx.body = ctx.session;
})
router.get('/set', async (ctx) => {
// 設置 session
ctx.session = {
id: Math.random().toString(36).substr(2), // 隨機 id
count: 0
}
ctx.body = ctx.session;
})
app.use(router.routes()).use(router.allowedMethods());
// 啟動服務監(jiān)聽本地3000端口
app.listen(3000, () => {
console.log('應用已經(jīng)啟動纱扭,http://localhost:3000');
})
上面的代碼中,通過 require();
引入了 koa 的中間件儡遮,并且在使用時傳遞了設置信息乳蛾,通過訪問 http://localhost:3000/set 和 http://localhost:3000/get 分別設置和獲取 session。當客戶端訪問對應 URL 時,服務端將 session 數(shù)據(jù)進行存儲肃叶,而在瀏覽器訪問 http://localhost:3000/get 將會看到 session 存儲的數(shù)據(jù):
{"id":"7zcj87rsyd","count":1}
通過查看請求蹂随,可以看到中間件管理了 session id 的產生以及 cookie 的設置,它會產生唯一的 SESSION_ID
返回給瀏覽器:
總結
通過前面的介紹因惭,我們了解到:
- Web 開發(fā)中引入 cookie 和 session 的原因(HTTP 的無狀態(tài))
- Cookie 和 session 的區(qū)別
- Cookie 包含的內容和用法
- Cookie 與 session 的工作方式
參考資料
https://www.allaboutcookies.org/cookies/
https://www.privacypolicies.com/blog/browser-cookies-guide/
https://stackoverflow.com/questions/31021764/where-does-chrome-store-cookies