為什么要cookie?
HTTP協議是無狀態的,也就是說客戶端和服務器端不需要建立持久的連接。由于客戶端和服務器的連接是基于一種請求應答模式,及客戶端和服務器建立一個連接,客戶端提交一個請求,服務器端收到請求后返回一個響應,然后二者就斷開連接。
既然客戶端和服務器在完成一次請求以后,彼此就斷開了連接,二者之間就不再有任何關系了;比如,用戶在頁面一進行了登錄,當用戶跳轉到了同一個Web應用的頁面二,那么如何在頁面二知道用戶已經進行了登錄呢?It’s a question!!! 當客戶端再次發起請求的時候,服務器端如何判斷兩次不同的請求來自同一個客戶端呢?
是的,服務器無法區分每一次請求之間的聯系。這就需要有一個狀態來標識每一次請求,如果兩次請求的狀態標識是一樣的,這就表明這兩個請求是從同一個客戶端發起的。
于是24歲的網景公司的moutulli針對這問題設計出cookie的雛形.
cookie工作原理
下面我通過瀏覽器向www.baidu.com發起請求,并簡單的將cookie的工作原理圖繪制出來。
cookie在客戶端和服務器之間進行傳遞信息的基本過程:
1.首次向百度發起首次請求;
2.當請求到達百度的服務器以后,百度的服務器需要生成響應,并會在響應的頭部寫入cookie信息;
服務器通過發送一個帶有Set-Cookie的HTTP消息響應頭來創建一個cookie,并設置cookie的一些屬性;
3.當客戶端瀏覽器接收到響應頭以后,會將cookie信息寫入本地進行管理;
4.當再次向百度服務器發起請求時,客戶端會將之前寫入的cookie一起發送過去;
客戶端通過發送一個帶有Cookie: name=value; name2=value2的HTTP請求頭來向服務器發送本地的cookie數據;
5.服務器接收到請求以后,從請求頭中獲得cookie信息,分析cookie數據,再向客戶端響應。
個人建議:對cookie的操作最好放在后臺.因為cookie本身是存儲在瀏覽器中的字符串,如果在前端用
document.cookie
來獲取cookie可能比較麻煩,需要分割字符串等;后臺通過cookie-parser
來解析你需要的cookie數據.
cookie可選參數
可選的 cookie 參數會影響將 cookie 發送給服務器端的過程,主要有以下幾種:
-
path
:表示cookie
影響到的路徑,匹配該路徑才發送這個cookie
。 -
expires
和maxAge
:告訴瀏覽器這個cookie
什么時候過期,expires
是 UTC 格式時間,maxAge
是cookie
多久后過期的相對時間。當不設置這兩個選項時,會產生session cookie
,session cookie
是transient
的,當用戶關閉瀏覽器時,就被清除。一般用來保存session
的session_id
。
secure
:當secure
值為true
時,cookie
在 HTTP 中是無效,在HTTPS
中才有效。
httpOnly
:瀏覽器不允許腳本操作document.cookie
去更改cookie
。一般情況下都應該設置這個為true
,這樣可以避免被xss
攻擊拿到cookie
。
cookie的生命周期
cookie是有生命周期的,一旦到了cookie的失效日期,客戶端的cookie就會被刪除。服務器在創建cookie時可以控制一個cookie可以在客戶端“存活”多長時間。在以下幾種情況下,cookie都會結束它自己的生命周期:
- 未指定過期時間的cookie:當服務器創建一個cookie的時候沒有指定對應的過期時間時,客戶端會將這類cookie寫入瀏覽器開辟的一塊內存中,當關閉瀏覽器以后,這塊內存也就被釋放了,對應的cookie也就是結束了它的生命;
- 指定過期時間的cookie:當服務器創建一個cookie的時候指定了對應的過期時間時,當到達了過期時間時,對應的cookie就會被刪除;
- 當瀏覽器中的cookie數量達到了限制時,那么瀏覽器就會按照某種策略刪除一些舊的cookie,騰出空間來創建新的cookie;
- 當然了,我們也可以手動的人為刪除cookie。
cookie的缺點
- 安全性:由于cookie在HTTP中是明文傳遞的,其中包含的數據都可以被他人訪問,可能會被篡改、盜用。
- 大小限制:cookie的大小限制在4KB左右,若要做大量存儲顯然不是理想的選擇。
- 增加流量:cookie每次請求都會被自動添加到Request Header中,無形中增加了流量。cookie信息越大,對服務器請求的時間也越長。
express-cookie-demo
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
app.get('/', function (req, res) {
res.send('Hello, world!');
});
app.get('/set-cookies', function (req, res) {
res.cookie('token', 'mike:123456').end();
});
app.get('/cookies', function (req, res) {
res.send(req.cookies);
});
app.listen(3000, function () {
console.log('Server listening at http://localhost:3000');
});
參考資料:
http://www.jellythink.com/archives/1389
http://wiki.jikexueyuan.com/project/node-lessons/cookie-session.html
https://segmentfault.com/a/1190000004743454