1、Django請求生命週期
在學習中間件以前,先了解一下Django的請求生命週期,以下圖:python
1)client表明瀏覽器,瀏覽器內部爲咱們封裝了socket,Django的WSGI模塊也封裝了socket;分析:django
2)當用戶在瀏覽器中輸入url時,瀏覽器會生成請求頭和請求體發給服務端,請求頭和請求體中會包含瀏覽器的動做(action),這個動做一般爲get或者post,體如今url之中;瀏覽器
3)請求到達Django服務器後,首先,WSGI根據http請求協議進行解包並將請求信息封裝到HttpRequest對象中;服務器
4)再依次通過Django的中間件的process_request方法(Django自帶7箇中間件,每一箇中間件都是一個類,類中必定有一個process_request方法);session
5)而後經過url控制器分發後,執行對應的視圖函數,視圖函數中能夠根據請求查詢相應的數據,獲得的數據能夠再傳給模板,通過render方法渲染後返回;socket
6)返回時再依次通過中間件的process_response方法;函數
7)再通過WSGI模塊,WSGI將按照http協議響應格式封裝響應信息,最後返回給客戶端(瀏覽器);post
8)客戶端瀏覽器接收到返回的數據,通過渲染後顯示給用戶;性能
2、中間件的概念
中間件,顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,而且在全局上改變django的輸入與輸出。由於改變的是全局,因此須要謹慎實用,用很差會影響到性能。學習
Django的中間件的定義:
1
|
Middleware
is
a framework of hooks into Django’s request
/
response processing. <br>It’s a light, low
-
level 「plugin」 system
for
globally altering Django’s
input
or
output.
|
若是你想修改請求,例如被傳送view中的HttpRequest對象。或者你想修改view返回的HttpResponse對象,這些均可以經過中間件(middleware)來實現。可能你還想在view執行以前作一些操做,這種狀況就能夠用 middleware來實現。
Django默認的Middleware:
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
每個中間件都有具體的功能。
3、自定義中間件
中間件中一共有四個方法:
process_request
process_view
process_exception
process_response
一、process_request,process_response
當用戶發起請求的時候會依次通過全部的中間件,這個時候是執行process_request,最後到達views的函數中,views函數處理後,再依次穿過中間件,這個時候是process_response,最後返回給請求者。
上述截圖中的中間件都是django自帶的,咱們也能夠本身定義一箇中間件,即本身寫一個類,可是必須繼承MiddlewareMixin。
需導入:from django.utils.deprecation import MiddlewareMixin
在 views.py:
def index(request): print("view函數...") return HttpResponse("OK")
在 Mymiddlewares.py:
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print("Md1請求") # return HttpResponse("Md1中斷") def process_response(self,request,response): print("Md1返回") return response class Md2(MiddlewareMixin): def process_request(self,request): print("Md2請求") def process_response(self,request,response): print("Md2返回") return response
打印結果:
Md1請求 Md2請求 view函數... Md2返回 Md1返回
注意:若是當請求到達Md1的時候直接不符合條件返回,即return HttpResponse("Md1中斷"),程序將把請求直接發給中間件1返回,而後依次返回到請求者,結果以下:
Md1請求 Md1返回
流程圖以下:
二、process_view
process_view(self, request, callback, callback_args, callback_kwargs)
Mymiddlewares.py修改以下:
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print("Md1請求") # return HttpResponse("Md1中斷") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md1view") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2請求") # return HttpResponse("Md2中斷") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("Md2view")
打印結果以下:
Md1請求 Md2請求 Md1view Md2view view函數... Md2返回 Md1返回
分析上面的過程,以下面流程圖:
當最後一箇中間的process_request到達路由關係映射以後,返回到中間件1的process_view,而後依次往下,到達views函數,最後經過process_response依次返回到達用戶。
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1請求") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("callback ") # 訪問index時打印<function index at 0x0000000003EF48C8> # 說明callback就是當前請求url對應的視圖函數名 response = callback(request,*callback_args,**callback_kwargs) return response
注意:process_view若是有返回值,會越過其餘的process_view以及視圖函數,可是全部的process_response都還會執行。
三、process_exception
process_exception(self, request, exception)
流程圖以下:
Mymiddlewares.py修改以下:
class Md1(MiddlewareMixin): def process_request(self,request): print("Md1請求") def process_response(self,request,response): print("Md1返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): # response=callback(request,*callback_args,**callback_kwargs) # return response print("md1 process_view...") def process_exception(self,request, exception): print("md1 process_exception...") class Md2(MiddlewareMixin): def process_request(self,request): print("Md2請求") def process_response(self,request,response): print("Md2返回") return response def process_view(self, request, callback, callback_args, callback_kwargs): print("md2 process_view...") def process_exception(self, request, exception): print("md2 process_exception...") return HttpResponse(exception)
當視圖函數出現錯誤時,打印結果以下(頁面接收到錯誤類型):
Md1請求 Md2請求 md1 process_view... md2 process_view... view函數... md2 process_exception... Md2返回 Md1返回
4、應用案例
一、作IP訪問頻率限制
某些IP訪問服務器的頻率太高,進行攔截,好比限制每分鐘不能超過20次。
二、URL訪問過濾
若是用戶訪問的是login視圖(放過);
若是訪問其餘視圖,須要檢測是否是有session認證,已經有了放行,沒有返回login,這樣就免得在多個視圖函數上寫裝飾器了!
5、源碼試讀
做爲延伸擴展內容,建議你能夠嘗試着讀一讀下面兩個django自帶的中間件:
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',