目錄html
首先咱們須要瞭解一下什麼是會話?咱們能夠把會話看成成客戶端與服務器之間的一次會晤,在一次會晤期間會有屢次請求和響應。例如你打電話給10086客服,那麼此時你就是客戶端,10086客服就是服務端,那麼一次會晤就是大家在打電話期間的聊天過程。直到某一方掛了電話,此時表示會話結束。在大家的通話過程當中,你會向10086發送屢次請求,那麼這些請求都會保存在一個會話中。python
在JavaWeb中,客戶端向服務器發出第一個請求開始,會話就開始了,直到客戶端關閉了瀏覽器會話結束。web
在一次會話中的多個請求須要共享數據,這就是會話跟蹤技術。例如在一個會話中的請求以下:數據庫
在以上此次會話中,當前用戶的信息必須是要在此次會話中共享的,由於登錄的是zhangsan,那麼轉帳和還款確定是用zhangsan用戶轉帳和還款,這就說明咱們必須在一個會話過程當中有共享數據的能力。django
HTTP協議是一種不保存狀態,即無狀態協議。HTTP協議自身不對請求和響應之間的通訊狀態進行保存。也就是說在HTTP這個級別,協議對於發送過的請求或響應都不作持久化處理。
瀏覽器
使用HTTP協議,每當有新的請求發送時,就會有對應的新響應產生。協議自己並不保留以前一切的請求或響應報文的信息。這是爲了更快的處理大量事務,確保協議的可伸縮性,而特地把HTTP協議設計的如此簡單的。安全
但是,隨着web的不斷髮展,因無狀態而致使業務處理變得棘手的狀況增多了。好比我們剛剛說的請求銀行、登錄、轉帳、還款的問題。雖然HTTP協議是無狀態協議,但爲了實現指望的保持狀態功能,因而引入了cookie技術。有了cookie再用HTTP協議通訊,就能夠管理狀態了。服務器
cookie翻譯成中文是小甜點、小餅乾的意思。在HTTP中它表示從服務器送給客戶端的小甜點。其實cookie是key-value結構,和python的字典比較相似。隨着服務器端的響應發送給客戶端瀏覽器,而後客戶端瀏覽器會把cookie保存起來,當下一次再訪問服務器時就把cookie再發送給服務器。cookie
cookie是由服務器端建立,而後經過響應發送給客戶端的一個鍵值對。客戶端會保存cookie,並會標註cookie的來源。當客戶端向服務器發出請求時會把全部這個服務器cookie的包含在請求中發送給服務器,這樣服務器就能夠識別客戶端了。
session
讓咱們用代碼級別來看一下cookie長什麼樣子?
首先咱們須要新建立一個項目,而後設置路由規則:
urls.py
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def login(request): return render(request, 'login.html')
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login頁面</title> </head> <body> <form action="" method="post"> {% csrf_token %} 用戶名 <input type="text" name="user"> 密碼 <input type="text" name="pwd"> <input type="submit" value="submit"> </form> </body> </html>
而後在model.py中建立模型類
from django.db import models # Create your models here. class UserInfo(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
使用數據庫遷移命令來生成數據庫:
python3 manage.py makemigrations python3 manage.py migrate
最後在數據庫中插入兩條記錄:
那麼當咱們把整個項目運行起來後,當咱們輸入用戶名和密碼若是正確以後,那麼就在瀏覽器設置一個cookie而後響應給客戶端,那麼咱們須要在views.py中去進行判斷了:
from django.shortcuts import render,HttpResponse,redirect from app01.models import UserInfo # Create your views here. def login(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: response = HttpResponse('登錄成功') response.set_cookie({'is_login': True}) return response return render(request, 'login.html')
此時我們在瀏覽器輸入正確的用戶和密碼後,讓咱們看下這次響應的內容:
此時的cookie已經放在響應體中了,當客戶端向此服務器發送請求的時候,就會攜帶上這個cookie,當咱們刷新此界面,就能夠看到了攜帶了此cookie:
那麼咱們能夠去模仿某網站了,若是你登錄過,那麼就進入index界面,若是沒有那就強制跳轉到登錄界面。首先咱們要寫一條路由規則:
urls.py
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), ]
views.py
from django.shortcuts import render,HttpResponse,redirect from app01.models import UserInfo # Create your views here. def login(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: response = HttpResponse('登錄成功') response.set_cookie('is_login', True) response.set_cookie('username', user.user) return response return render(request, 'login.html') def index(request): is_login = request.COOKIES.get('is_login') if is_login: username = request.COOKIES.get('username') return render(request, 'index.html', locals()) else: return redirect('/login/')
此時views.py中就是當用戶再login界面登錄後,系統會設置cookie將當前狀態和登錄用戶名記錄下來而後響應給客戶端,而後當用戶訪問index界面中,首先就去判斷用戶是否登錄,若是沒有登錄那麼就重定向到login頁面中,若是登錄則跳出歡迎界面。
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> <h3>這是主界面</h3> <p>hello,{{ username }}</p> </body> </html>
那麼下圖就是瀏覽器訪問index所攜帶的cookie:
class HttpResponseBase: def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False, httponly=False, samesite=None): """ Set a cookie. ``expires`` can be: - a string in the correct format, - a naive ``datetime.datetime`` object in UTC, - an aware ``datetime.datetime`` object in any time zone. If it is a ``datetime.datetime`` object then calculate ``max_age``. """ self.cookies[key] = value if expires is not None: if isinstance(expires, datetime.datetime): if timezone.is_aware(expires): expires = timezone.make_naive(expires, timezone.utc) delta = expires - expires.utcnow() # Add one second so the date matches exactly (a fraction of # time gets lost between converting to a timedelta and # then the date string). delta = delta + datetime.timedelta(seconds=1) # Just set max_age - the max_age logic will set expires. expires = None max_age = max(0, delta.days * 86400 + delta.seconds) else: self.cookies[key]['expires'] = expires else: self.cookies[key]['expires'] = '' if max_age is not None: self.cookies[key]['max-age'] = max_age # IE requires expires, so set it if hasn't been already. if not expires: self.cookies[key]['expires'] = http_date(time.time() + max_age) if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = domain if secure: self.cookies[key]['secure'] = True if httponly: self.cookies[key]['httponly'] = True if samesite: if samesite.lower() not in ('lax', 'strict'): raise ValueError('samesite must be "lax" or "strict".') self.cookies[key]['samesite'] = samesite
那麼經過這段源碼咱們能夠看出來除了響應體設置cookie由key-value參數,還有一些其餘的參數,例如超長時間max_age,cookie生效的路徑path等。
有時候咱們但願用戶在登錄某網站一段時間後cookie就過時,那麼咱們就能夠設置超長時間
views.py
from django.shortcuts import render,HttpResponse,redirect from app01.models import UserInfo # Create your views here. def login(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: response = HttpResponse('登錄成功') response.set_cookie('is_login', True, max_age=20) # 超長時間 response.set_cookie('username', user.user) return response return render(request, 'login.html') def index(request): is_login = request.COOKIES.get('is_login') if is_login: username = request.COOKIES.get('username') return render(request, 'index.html', locals()) else: return redirect('/login/')
那麼當咱們用戶登錄login頁面後,再去訪問index界面,等待15秒鐘後會自動重定向到login界面。
expires默認None ,cookie失效的實際日期/時間。
這個和max_age不同的是這個要寫時間的字符串。
views.py
import datetime date = datetime.datetime.strftime(year=2018, month=11, day=21, hour=3, minute=51, second=0) # 東八區 response.set_cookie('is_login', True, expires=date)
那麼這樣寫的意思就是在2018年11月22日 上午11時51分00秒這個cookie失效。能夠自行去測試的,這個我就不演示了。
cookie生效的路徑,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣能夠避免將cookie傳給站點中的其餘應用。也就是說:若是個人index頁面須要cookie,那麼我就只須要在path後面設置爲此頁面就能夠了,其他的並不須要。
views.py
def login(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: response = HttpResponse('登錄成功') import datetime # date = datetime.datetime.strftime(year=2018, month=11, day=21, hour=3, minute=51, second=0) # 東八區 response.set_cookie('is_login', True, path='/login/') response.set_cookie('username', user.user) return response return render(request, 'login.html')
此時我們設置的路徑就是login頁面,爲了驗證效果,當咱們輸入正確的信息後,當再次輸入地址進入index界面中,由於cookie生效路徑沒有index,那麼就會自動跳轉到login頁面了。
本次暫不演示。
response.delete_cookie("cookie_key",path="/",domain=name)
session是一個服務器端技術,利用這個技術,服務器在運行時能夠爲每個用戶的瀏覽器建立一個獨享的session對象,因爲session爲用戶瀏覽器獨享,因此用戶在訪問服務器web資源時,能夠把各自的數據存放在各自的session表中,當用戶再去訪問服務器中的其餘web資源時,其餘Web資源再從用戶各自的session中取出數據爲用戶服務。
session基於cookie實現的會話跟蹤,cookie存放在客戶端一旦丟失的話就會對用戶的數據構成威脅。
咱們來看一下cookie的保存:
當咱們輸入正確的帳號和密碼後,由服務器端響應體設置的cookie就會傳給客戶端,那麼客戶端再次請求的時候就會拿這個cookie去請求,由於是明文的、存放在瀏覽器的將變的十分不安全。
那麼讓咱們來看一下session怎麼作的?
首先設置兩條路由規則views.py:
path('login_session', views.login_session), path('index_session', views.index_session),
同時設置視圖函數views.py
# session def login_session(request): return render(request, 'login.html') def index_session(request): return render(request, 'index.html')
那麼session是怎麼和cookie不一樣的呢?
views.py
def login_session(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: request.session['is_login'] = True request.session['username'] = user.user return HttpResponse('登錄成功') return render(request, 'login.html')
當咱們去瀏覽器訪問下能夠看到此時的sessionid:
在這裏不一樣的是session和cookie建立的步驟不一樣:
那麼到最後返回到客戶端的就是一個sessionid,當客戶端瀏覽器再請求服務器時,服務器就會根據這個sessionid在djano_session表中查找這麼一條記錄,咱們在建立數據庫的時候django_session表已經自動建立好了。
那麼此時我們設置一個視圖函數,看看session的數據是怎麼找到的:
views.py
def index_session(request): print(request.session.get('is_login')) is_login = request.session.get('is_login') if not is_login: return redirect('/login_session/') username = request.session.get('username') return render(request, 'index.html', locals())
session去找數據也是三個步驟,首先要確認是否是第一次訪問,若是是那麼就添加詞條記錄,若是不是那就更新操做:
刪除session值:del request.session['username']
views.py
def index_session(request): print(request.session.get('is_login')) del request.session['username'] is_login = request.session.get('is_login') if not is_login: return redirect('/login_session/') # username = request.session.get('username') return render(request, 'index.html', locals())
那麼此時我們訪問login_session後再訪問index_session的時候,此時的username被咱們刪掉了,而後此時刷新界面是這樣的:
flush():刪除當前的會話數據並刪除會話的Cookie。
logout.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> <h3>這是主界面</h3> <p>hello,{{ username }}</p> <a href="/logout/">註銷</a> </body> </html>
views.py
def logout(request): request.session.flush() return redirect('/login_session/')
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> <h3>這是主界面</h3> <p>hello,{{ username }}</p> <a href="/logout/">註銷</a> </body> </html>
此時點擊註銷標籤,此時就會刪除當前會話的cookie。
django中默認支持session的,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。
配置settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認) SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時(默認) SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改以後才保存(默認)
views.py
def login_session(request): if request.method == 'POST': user = request.POST.get('user') pwd = request.POST.get('pwd') user = UserInfo.objects.filter(user=user, pwd=pwd).first() if user: request.session['is_login'] = True request.session['username'] = user.user import datetime now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') request.session['time'] = now return HttpResponse('登錄成功') return render(request, 'login.html')
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Index</title> </head> <body> <h3>這是主界面</h3> {# <p>hello,{{ username }}</p>#} <p>上次登錄時間:{{ time }}</p> <a href="/logout/">註銷</a> </body> </html>
基於cookie也是相似的作法。