本篇文章的主題,用 Node.js 搭一個服務,來看看 Cookie 的實際應用場景html
咱們新建一個文件 main.js
,並在 main.js
寫入如下代碼:node
const express = require('express') const app = express() app.listen(3000, err => { if (err) { return console.log(err) } console.log('---- 打開 http://localhost:3000 吧----') }) app.get('/', (req, res) => { res.send('<h1>hello world!</h1>') })
node main.js // 一個本地服務就跑起來了,如今打開 http://localhost:3000 // 就能夠看到一個大大的 hello world!
在介紹 Cookie 是什麼以前,咱們來看看 Cookie 是如何工做的:git
1. 首先,咱們假設當前域名下仍是沒有 Cookie 的 2. 接下來,瀏覽器發送了一個請求給服務器(這個請求是還沒帶上 Cookie 的) 3. 服務器設置 Cookie 併發送給瀏覽器(固然也能夠不設置) 4. 瀏覽器將 Cookie 保存下來 5. 接下來,之後的每一次請求,都會帶上這些 Cookie,發送給服務器
咱們來驗證一下github
// 修改 main.js app.get('/', (req, res) => { // 服務器接收到請求,在給響應設置一個 Cookie // 這個 Cookie 的 name 爲 testName // value 爲 testValue res.cookie('testName', 'testValue') res.send('<h1>hello world!</h1>') }) // 保存以後,重啓服務器 // node main.js
如今打開 http://localhost:3000
express
Request Headers
並無 Cookie 這個字段Response Headers
有了 Set-Cookie
這個字段
如今咱們刷新一下頁面,至關於從新向 http://localhost:3000/
這個地址發起了一次請求。segmentfault
如今咱們就能夠看到 Cookie 字段已經帶上了,再刷新幾回看 Cookie 也仍是在的。瀏覽器
JS 提供了獲取 Cookie 的方法:document.cookie
,咱們先去設置多幾個 Cookie。安全
app.get('/', (req, res) => { res.cookie('testName0', 'testValue0') res.cookie('testName1', 'testValue1') res.cookie('testName2', 'testValue2') res.cookie('testName3', 'testValue3') res.send('<h1>hello world!</h1>') })
咱們能夠看到,Cookie 就是一段字符串。但這個字符串是有格式的,由鍵值對 key=value
構成,鍵值對之間由一個分號
和一個空格
隔開。服務器
說了這麼多,你們應該知道 Cookie 是什麼吧。整理一下有如下幾個點:cookie
每一個 Cookie 都有必定的屬性,如何時失效,要發送到哪一個域名,哪一個路徑等等。在設置任一個 Cookie 時均可以設置相關的這些屬性,固然也能夠不設置,這時會使用這些屬性的默認值。
expires / max-age
都是控制 Cookie 失效時刻
的選項。若是沒有設置這兩個選項,則默認有效期爲 session,即會話 Cookie。這種 Cookie 在瀏覽器關閉後就沒有了。
expires
選項用來設置 Cookie 什麼時間內有效,expires
實際上是 Cookie 失效日期。expires
必須是 GMT 格式的時間(能夠經過 new Date().toGMTString()
或者 new Date().toUTCString()
來得到)
app.get('/', (req, res) => { // 這個 Cookie 設置十秒後失效 res.cookie('testName0', 'testValue0', { expires: new Date(Date.now() + 10000) }) // 這個 Cookie 不設置失效時間 res.cookie('testName1', 'testValue1') res.send('<h1>hello world!</h1>') })
上面的代碼服務器設置了兩個 Cookie,一個設置了失效刻,另一個沒有設置,也就是默認的失效時刻 session。如今咱們重啓服務而且刷新一下頁面。
如今響應頭部已經加上了響應的設置失效時刻的字段了。在控制檯輸入下面的代碼。
console.log(`如今的 cookie 是:${document.cookie}`) setTimeout(() => { console.log(`5 秒後的 cookie 是:${document.cookie}`) }, 5000) setTimeout(() => { console.log(`10 秒後的 cookie 是:${document.cookie}`) }, 10000)
因此,Cookie 的失效時刻到了以後,經過 document.cookie 就訪問不到這個 Cookie 了,固然之後發送請求也不會再帶上這個失效的 Cookie 了。
expires
是 http/1.0 協議中的選項,在新的 http/1.1 協議中 expires
已經由 max-age
選項代替,二者的做用都是限制 Cookie 的有效時間。expires
的值是一個時間點 (Cookie 失效時刻 = expires
),而 max-age
的值是一個以秒
爲單位時間段 (Cookie 失效時刻 = 建立時刻 + max-age
)
// 設置 max-age,就是設置從 cookie 建立的時刻算起 // 再過多少秒 cookie 就會失效 app.get('/', (req, res) => { res.cookie('testName0', 'testValue0', { // express 這個參數是以毫秒來作單位的 // 實際發送給瀏覽器就會轉換爲秒 // 十秒後失效 maxAge: 10000 }) res.cookie('testName1', 'testValue1') res.send('<h1>hello world!</h1>') })
若是同時設置了 max-age 和 expires,以 max-age 的時間爲準。
app.get('/', (req, res) => { res.cookie('name0', 'value0') res.cookie('name1', 'value1', { expires: new Date(Date.now() + 30 * 1000), maxAge: 60 * 1000 }) res.cookie('name2', 'value2', { maxAge: 60 * 1000 }) res.send('<h1>hello world!</h1>') })
name
、domain
和 path
能夠標識一個惟一的 Cookie。domain
和 path
兩個選項共同決定了 Cookie 什麼時候被瀏覽器自動添加到請求頭部中發送出去。具體是什麼原理請看 Cookie 的做用域和做用路徑 這個章節。
若是沒有設置這兩個選項,則會使用默認值。domain
的默認值爲設置該 Cookie 的網頁所在的域名,path
默認值爲設置該 Cookie 的網頁所在的目錄。
secure 選項用來設置 Cookie 只在確保安全的請求中才會發送。當請求是 HTTPS 或者其餘安全協議時,包含 secure 選項的 Cookie 才能被保存到瀏覽器或者發送至服務器。
默認狀況下,Cookie 不會帶 secure 選項(即爲空)。因此默認狀況下,不論是 HTTPS 協議仍是 HTTP 協議的請求,Cookie 都會被髮送至服務端。
這個選項用來設置 Cookie 是否能經過 js 去訪問。默認狀況下,Cookie 不會帶 httpOnly
選項(即爲空),客戶端是能夠經過 js 代碼去訪問(包括讀取、修改、刪除等)這個 Cookie 的。當 Cookie 帶 httpOnly
選項時,客戶端則沒法經過 js 代碼去訪問(包括讀取、修改、刪除等)這個 Cookie。
看看代碼吧,修改 main.js,保存重啓服務,刷新頁面。
app.get('/', (req, res) => { res.cookie('notHttpOnly', 'testValue') res.cookie('httpOnlyTest', 'testValue', { httpOnly: true }) res.send('<h1>hello world!</h1>') })
看圖,設置了 httpOnly
的 Cookie 多了一個勾。並且經過 document.cookie
沒法訪問到那個 Cookie。
在客戶端是不能經過 js 代碼去設置 一個 httpOnly
類型的 Cookie 的,這種類型的 Cookie 只能經過服務端來設置,發送請求的時候,咱們看到請求頭仍是會帶上這個設置了 httpOnly
的 Cookie,以下圖。
明確一點:Cookie 能夠由服務端設置,也能夠由客戶端設置。看到這裏相信你們均可以理解了吧。
看回剛剛的那張圖,咱們設置了不少個 Cookie。
在網頁即客戶端中咱們也能夠經過 js 代碼來設置 Cookie。
document.cookie = 'name=value'
能夠設置 Cookie 的下列選項:expires、domain、path,各個鍵值對之間都要用 ;
和 空格
隔開
document.cookie='name=value; expires=Thu, 26 Feb 2116 11:50:25 GMT; domain=sankuai.com; path=/';
只有在 https 協議的網頁中,客戶端設置 secure 類型的 Cookie 才能成功
客戶端中沒法設置 HttpOnly 選項
Cookie 的 name、path 和 domain 是惟一標識一個 Cookie 的。咱們只要將一個 Cookie 的 max-age 設置爲 0,就能夠刪除一個 Cookie 了。
let removeCookie = (name, path, domain) => { document.cookie = `${name}=; path=${path}; domain=${domain}; max-age=0` }
在說這個做用域以前,咱們先來對域名作一個簡單的瞭解。
子域,是相對父域來講的,指域名中的每個段。各子域之間用小數點分隔開。放在域名最後的子域稱爲最高級子域,或稱爲一級域,在它前面的子域稱爲二級域。
如下圖爲例,news.163.com
和 sports.163.com
是子域,163.com
是父域。
當 Cookie 的 domain 爲 news.163.com
,那麼訪問 news.163.com
的時候就會帶上 Cookie;
當 Cookie 的 domain 爲 163.com
,那麼訪問 news.163.com
和 sports.163.com
就會帶上 Cookie
當 Cookie 的 domain 是相同的狀況下,也有是否帶上 Cookie 也有必定的規則。
在子路徑內能夠訪問訪問到父路徑的 Cookie,反過來就不行。
看看例子,仍是先修改 main.js
app.get('/parent', (req, res) => { res.cookie('parent-name', 'parent-value', { path: '/parent' }) res.send('<h1>父路徑!</h1>') }) app.get('/parent/childA', (req, res) => { res.cookie('child-name-A', 'child-value-A', { path: '/parent/childA' }) res.send('<h1>子路徑A!</h1>') }) app.get('/parent/childB', (req, res) => { res.cookie('child-name-B', 'child-value-B', { path: '/parent/childB' }) res.send('<h1>子路徑B!</h1>') })
下面這裏的 「域」 應該改成路徑