前提
51 也有個文章跟我一樣,是我自己投的稿哈
為什么要用Session和Cookie?
簡單一句話,因為 Session 和 Cookie 可以記錄用戶狀態信息
嘶..這到底啥意思呢?
背景一:動態網頁的出現
什么是靜態網頁
- 含義:一個網頁的內容是 HTML 代碼編寫的,文字、圖片等內容均可通過HTML代碼指定了
- 優勢:加載速度快,編寫簡單
- 劣勢:可維護性差,擴展性差,不能根據URL顯示不同的內容;例如:在 URL 傳入一個name參數想在網頁上顯示,靜態網頁是無法做到的
- 總結:弊大於利
動態網頁的誕生
- 動態網頁可以動態解析 URL 中參數的變化,關聯數據庫並動態呈現不同的頁面內容,非常靈活多變
- 現在遇到的大多數網站都是動態網站,不再是一個簡單的 HTML 頁面,可能由 JSP、PHP、Python 等語言編寫的,功能比靜態網頁強大和豐富太多
場景:一個需要登錄的動態網站,在登錄后需要保持登錄狀態,以便后續訪問網站其他網頁;那么我們要通過什么來保存這個登錄態呢?
背景二:HTTP是無狀態協議
HTTP無狀態是指?
HTTP協議對事務處理是沒有記憶能力,也就是說服務器不知道客戶端是什么狀態
這是什么意思呢?
- 當我們向服務器發送請求后,服務器解析處理請求,然后返回響應,服務器負責完成這個過程(也是一個事務)
- 而這個過程是獨立的,服務器不會記錄前后狀態的變化,也就是缺少狀態記錄
無狀態導致的后果?
- 意味着后續發出的請求需要處理前面請求的響應,則必須重傳
- 這也導致需要額外傳遞一些前面的重復請求,才能獲取后續響應
- 但為了保持前后狀態,我們也不能將前面的請求全部重傳一次,這太浪費資源了
- 就好像如果一個網站每次發出一個請求前都要先發出一次登錄請求,這無疑大大增加了資源浪費程度
舉栗子:百度
網站常常需要記錄訪問者的一些基本信息,例如:用戶是否登錄、用戶登錄名稱、密碼、用戶在 Web 站點購物的方式或用戶訪問該站點的次數
舉個例子,用戶在沒有登錄 baidu 時,此時用戶的身份是游客,baidu 首頁的界面如下圖所示:
當用戶登錄 baidu 頁面后,此時用戶的身份是已登錄用戶,可以看到頁面的右上角顯示了用戶的名稱,如下圖所示
- 可以看出,baidu 服務端能夠辨別用戶的身份,根據用戶是否登錄顯示不同的內容
- 如果用戶的身份是游客,則顯示登錄
- 如果是已登錄用戶,則顯示用戶的名稱
Seesion和Cookie的誕生
上圖可以看出,Session 和 Cookie 在一個網站中各自發揮的作用
使用 Cookie 辨別用戶的身份
- 網站為了辨別用戶身份、進行會話跟蹤需要把一些數據(例如:登錄狀態、用戶名稱)儲存在用戶本地終端上,這些數據被稱為 Cookie
- 以登錄 baidu 為例子,用戶在沒有登錄 baidu 時,訪問的網頁 URL 是 https://www.baidu.com
- 在登錄 baidu 后,訪問的網頁 URL 仍然是 https://www.baidu.com
- 訪問的頁面 URL 相同,但是這兩次訪問呈現的結果不相同,登錄前沒有顯示用戶名,登錄后顯示了用戶名
那服務端是怎么區分兩個請求呢?
- 用戶登錄 baidu
- baidu 服務端會生成一個用戶 ID
- baidu 服務端將這個用戶 ID 發送給瀏覽器
- 瀏覽器收到這個用戶 ID 后,會將這個用戶 ID 保存在用戶本地終端
- 瀏覽器再次訪問 baidu 站點時,瀏覽器會將保存在本地的用戶 ID 發給 baidu 服務端
- 服務端收到瀏覽器發送的用戶 ID 后,就知道此次請求來自於一個已登錄的用戶
以上交互過程中,保存在客戶端的用戶ID 就是 Cookie
實際場景
- 當我們登錄之后,服務端就會創建一個屬於當前用戶的 Session,里面保存的就是當前用戶的信息;
- 然后瀏覽器會根據服務器的響應頭中 Set-Cookie 字段生成相關 Cookie,相當於一個用戶憑證
- 只需要在下次請求時攜帶這些 Cookie,服務器就能通過 Cookie 來判斷用戶是否是登錄狀態,然后返回對應的響應
不好理解?繼續往下看!
生動形象理解Cookie和Session的關系
- Session 是保存在服務器端,Cookie 是保存在客戶端
- 每次用戶訪問網站的時候,相當於去串門
- 用戶帶着 cookie 去服務器家,當當當敲門
- 服務器問是誰啊
- 用戶:是我(cookie)啊
- 服務器:讓我來確認一下(session確認)
- 服務器確認完畢后,放用戶進門
實際網站登錄請求的響應頭
- 這是一個網站登錄之后返回的響應頭,可以看到服務器要求瀏覽器設置的 Cookies 有好幾個;這就是 Cookies 的來源,而 token 一般會作為用戶的唯一憑證【登錄成功,響應頭set-cookies,瀏覽器設置Cookies】
- 當瀏覽器下一次再請求該網站時,瀏覽器會把這些Cookies放到請求頭一起提交到服務器;而Cookies攜帶了SessionID信息(x-token)【再次請求,帶上 cookies,包含 SessionID】
- 服務器通過 SessionID 即可找到對應的用戶 Session 信息,然后判斷該用戶的登錄狀態【服務器根據 SessionID 獲取用戶信息】
- 如果 Session 中某些設置登錄狀態的變量是有效期內的,證明用戶處於登錄狀態【Session 有效,用戶已登錄】
- 此時服務器就會返回需要登錄之后才可以查看的網頁內容,瀏覽器再進行解析便可以看到了【返回請求響應內容】
- 當 Cookie 無效或者 Session 已過期后,我們再訪問網站就需要重新登錄了【Cookie 無效,Session 過期,需要再次登錄】
使用 Cookie、Session 最簡單的流程圖
Session和Cookie在登錄功能上的協同關系
Session
- 是在服務端保存的一個數據結構
- 用來存儲用戶的信息(比如登錄狀態、用戶名稱)
- Session 數據可以保存在內存(比如 Redis)、文件或數據庫中
- Session 有一個唯一標識 SessionID,會對應一個用戶
- 在服務端通過 SessionID 會找到特定的一個用戶數據
小栗子
- 假設有 2 個用戶:用戶 A 和用戶 B;
- 在服務端存在 2 個 Session,用於存儲用戶 A 和用戶 B 的數據
在服務端通過 SessionID 查找 Session 的過程如下
- 每一個 Session 有一個唯一標識,用戶A 的 SessionID 為0,用戶B 的 SessionID 為1
- 用戶訪問網站時,會把自己的 SessionID 作為 Cookie 發送給服務端
- 服務端根據請求中的 SessionID 來查找對應的 Session
實際場景
- 在Web中,Session對象用來存儲特定用戶 Session 所需的屬性和配置信息,這樣用戶在應用程序的Web頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶 Session 中存在下去
- 當用戶請求網頁時,該用戶還沒有 Session,則Web服務器將自動創建一個 Session 對象
- 當 Session 過期或被放棄后,服務器將終止該 Session
Cookie
某些網站為了辨別用戶身份,進行 Session 跟蹤而存儲在用戶本地終端上的數據
會話Cookie和持久Cookie
會話Cookie
可以將打開瀏覽器-關閉瀏覽器理解成一個會話,會話Cookie的有效期僅在瀏覽器打開期間;而會話Cookie是存在瀏覽器內存里的
實際場景:涉及錢,涉及利益、機密內容的網站一般都是會話Cookie,如企業郵箱等
持久Cookie
持久Cookie是存在客戶端本地硬盤中,不受瀏覽器關閉影響,下次再次訪問該網站時還能繼續使用,用於長久保持用戶登錄狀態
實際場景:可以勾選【自動登錄】、【30天內自動登錄】的網站用的就是持久Cookie
持久Cookie發出請求時,客戶端與服務器之間的時序圖
瀏覽器中看Cookie
- Name:Cookie 的名稱。Cookie 一旦創建,名稱便不可更改
- Value:Cookie 的值。如果值為 Unicode 字符,需要為字符編碼。如果值為二進制數據,則需要使用 BASE64 編碼。
- Domain:Cookie注入的域名,如.baidu.com下的Cookie,只要Host以.baidu.com結尾的域名都能訪問該Cookie
- Path:允許使用該Cookie的路徑,一般都為 /
- Expires/Max-Age:Cookie失效時間,若沒有指定失效時間則默認當瀏覽器關閉時Cookie失效
- Size:Cookie大小
- HttpOnly:若True,則不允許腳本來訪問該Cookie(如:JS)
- Secure:Cookie是否僅被使用安全協議傳輸,默認為False
敲重點的知識點
“只要關閉瀏覽器,Session 就消失了” —— 錯!
實際場景:去健身房辦理的會員卡,除非你自己要求銷卡,不然店家不會隨意銷掉你的卡
所以,對於 Session 也是一樣的,登錄的時候服務器幫你生成了一個 Session,是不會輕易刪除你的 Session,除非你自己提出要刪除 或 Session有效期過了;而一般我們會通過【退出】來刪除觸發服務器刪除 Session
當我們關閉瀏覽器時,瀏覽器是不會通知服務器說它要關閉,所以服務器根本不知道瀏覽器已關閉,造成這樣的誤解全都是因為:
- 一般情況下,網站都會用 Cookie 來保存 SessionID 信息的
- 當你的 Cookie 是會話 Cookie 時,關閉瀏覽器 Cookie 就會消失
- 再次打開網站也找不回之前的那個 Cookie 對應的 SessionID
- 所以無法通過原來的 SessionID 在服務器查找對應用戶的登錄狀態,只能重新登錄生成新的 Cookie 來記錄新的 SessionID
如何解決?
就是將 Cookie 設置為持久 Cookie,當你關閉瀏覽器再打開網站時,還是能從本地讀取到 Cookie,從而獲取到原來的 SessionID,以此來保持登錄狀態
另外
而恰恰因為關閉瀏覽器並不會讓服務器主動刪除 Session,為了避免服務器的資源浪費,一般服務器都會為每個 Session 設置一個失效時間,當 Session 的時間超過失效時間時,服務器會自動刪除 Session