cookie和session這兩個詞想必你們都不陌生,在HTTP交互中常常會涉及到這兩個概念。可是它們的做用究竟是什麼?兩者之間到底有什麼區別與聯繫呢?mysql
根據百度百科的定義:Cookie,類型爲「小型文本文件」,是某些網站爲了辨別用戶身份,進行Session跟蹤而儲存在用戶本地終端上的數據(一般通過加密)。web
用大白話說,就是:sql
由於HTTP是無狀態的協議,每一次請求之間都是徹底獨立的。但爲了實現web應用的交互,必須將同一個用戶的屢次請求關聯起來,才能產生有意義的行爲。數據庫
最典型的例子就是網購時添加商品到購物車,既然HTTP是無狀態協議,那麼服務器怎麼知道商品應該添加到哪一個用戶的購物車中呢?這就是cookie的做用了。django
用戶成功登陸電商網站後,服務器會生成一個登陸憑據,並經過response header中的 Set-Cookie 字段將其返回給用戶瀏覽器,通知其保存該cookie信息。編程
# 用於舉例,實際的cookie是通過加密的
Set-Cookie: uid=1
複製代碼
瀏覽器通常默認會將該cookie保存在用戶電腦某個目錄下的一個文本文件中,後續對該網站發起的request header中,都會攜帶該cookie。瀏覽器
這樣服務器在收到用戶請求的同時,也能夠從請求攜帶的cookie中知道該請求是來自哪一個用戶了。這樣就實現了用戶登陸狀態的保持。緩存
用戶添加商品A到其購物車時,服務器能夠修改cookie字段,將商品A的信息追加到cookie中,這樣就實現了將商品A與用戶關聯到一塊兒的行爲。bash
Set-Cookie: uid=1;prod=A
複製代碼
當用戶又添加了商品B到購物車中時,服務器又會將商品B的信息追加到cookie中。服務器
Set-Cookie: uid=1;prod=A; prod=B
複製代碼
等到用戶結帳的時候,服務器就能夠從請求攜帶的cookie中獲取到該用戶選擇的全部商品信息。
咱們常說的session,實際上有兩層概念。
首先是它的抽象概念:在用戶端與服務端之間一對一連續的交互,抽象爲一個用戶會話,也就是session。好比從用戶登陸到登出之間進行的一系列交互,都屬於同一個session。
其次是它的實際概念:爲了實現用戶會話的保持,服務端經過建立session對象記錄了用戶登陸後的各類信息,好比用戶名,用戶的操做等等。
session是服務端上對一個請求用戶進行標識的惟一信息,並將session的信息經過cookie返回給用戶,這樣就實現了在用戶端和服務端對用戶會話的跟蹤。
cookie是保存在客戶端的,好比用戶電腦上,一般是保存在一個文本中;而session是保存在服務端的,一般保存在數據庫或者緩存中,也能夠保存在文件系統中。
cookie是HTTP協議中的概念,位於request header中,服務器能夠經過response header中的Set-Cookie字段設置和修改返回給客戶端的cookie;而session是一個服務端層面的概念,不通的編程語言可能有不一樣的實現方式,其目的都是爲了記錄保持用戶的狀態。
咱們常說的session會話保持,實際上就是經過藉助cookie的特性,將服務端保存的session狀態返回給客戶端,並在整個用戶會話過程當中經過cookie進行持續的交互,進而實現抽象層面的session會話保持。
因此說cookie自己並無和session有必然的聯繫,它只是咱們用來實現session跟蹤的一種經常使用手段。
Django是經過中間件的形式支持session的。在建立項目時默認就會在settings.py中配置好session中間件。
INSTALLED_APPS = [
'django.contrib.sessions',
]
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
]
複製代碼
Django默認會將session信息保存在數據庫中,能夠經過 manage.py migrate 生成session信息表。若是對性能要求比較高,也能夠將session信息配置保存到緩存中。
mysql> desc django_session;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| session_key | varchar(40) | NO | PRI | NULL | |
| session_data | longtext | NO | | NULL | |
| expire_date | datetime(6) | NO | MUL | NULL | |
+--------------+-------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
複製代碼
能夠看到,django_session表中有3個字段,其中:
session_data 實際對用戶信息進行加密後生成的密文,能夠解密;
session_key是根據session_data密文生成的一串隨機字符串,自己並沒有實際意義,僅用於插入到cookie中返回給客戶端,並在用戶發起請求時對請求中攜帶的cookie與django_session表中的session_key進行匹配,查詢是否有匹配的session_data;
expire_date記錄了該session的過時時間。
在發起登陸請求後,服務端在response header中攜帶了Set-Cookie字段,內容包含了csrftoken,以及本次會話的sessionid。
(cookie中的csrftoken機制請見 CSRF攻擊與Django防範)
Set-Cookie: csrftoken=ATfjCEJZVaN9zTYnSHPzSRJhWfVfFlxntOYyu2f64j4mf9clzigVxsBIFN293uu3; expires=Sun, 28 Feb 2021 14:58:22 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Set-Cookie: sessionid=j0b9jsiiumwfjzmt9k3tw05aw7q5xk2n; expires=Sun, 15 Mar 2020 14:58:22 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax
複製代碼
在Django數據庫中,能夠看到django_session表中也有對應的記錄
在登陸後的下一次請求中,能夠看到request header中的cookie中已經攜帶了服務端返回的sessionid
至此,經過服務端的session機制,並藉助HTTP協議的cookie機制,就實現了HTTP無狀態協議的會話保持,用戶也就能夠進行愉快的頁面交互了。