了解 cookie 和 session

為何需要 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_message.png

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 服務端就能夠對訪問的用戶進行辨別。

cookie_and_session.jpg

舉個栗子:

商店發(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/sethttp://localhost:3000/get 分別設置和獲取 session。當客戶端訪問對應 URL 時,服務端將 session 數(shù)據(jù)進行存儲肃叶,而在瀏覽器訪問 http://localhost:3000/get 將會看到 session 存儲的數(shù)據(jù):

{"id":"7zcj87rsyd","count":1}

通過查看請求蹂随,可以看到中間件管理了 session id 的產生以及 cookie 的設置,它會產生唯一的 SESSION_ID 返回給瀏覽器:

而在 redis 中也能夠看到存儲的 session 數(shù)據(jù):
session_id_response.png
session_data_redis.png

總結

通過前面的介紹因惭,我們了解到:

  • 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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末岳锁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蹦魔,更是在濱河造成了極大的恐慌激率,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勿决,死亡現(xiàn)場離奇詭異乒躺,居然都是意外死亡,警方通過查閱死者的電腦和手機低缩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門嘉冒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人咆繁,你說我怎么就攤上這事讳推。” “怎么了玩般?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵银觅,是天一觀的道長。 經(jīng)常有香客問我壤短,道長设拟,這世上最難降的妖魔是什么慨仿? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任久脯,我火速辦了婚禮,結果婚禮上镰吆,老公的妹妹穿的比我還像新娘帘撰。我一直安慰自己,他們只是感情好万皿,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布摧找。 她就那樣靜靜地躺著,像睡著了一般牢硅。 火紅的嫁衣襯著肌膚如雪蹬耘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天减余,我揣著相機與錄音综苔,去河邊找鬼。 笑死,一個胖子當著我的面吹牛如筛,可吹牛的內容都是我干的堡牡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼杨刨,長吁一口氣:“原來是場噩夢啊……” “哼晤柄!你這毒婦竟也來了?” 一聲冷哼從身側響起妖胀,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芥颈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后做粤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浇借,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年怕品,在試婚紗的時候發(fā)現(xiàn)自己被綠了妇垢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡肉康,死狀恐怖闯估,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情吼和,我是刑警寧澤涨薪,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站炫乓,受9級特大地震影響刚夺,放射性物質發(fā)生泄漏。R本人自食惡果不足惜末捣,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一侠姑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧箩做,春花似錦莽红、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至燃辖,卻和暖如春鬼店,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背黔龟。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工妇智, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留确沸,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓俘陷,卻偏偏與公主長得像罗捎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拉盾,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355