文章目錄
- 一、什么是中間件
- 二、中間件有什么用
- 三、Django自定義中間件
- 中間件中主要方法及作用
- `創建自定義中間件的步驟:`
- process_request與process_response方法
- process_view方法
- process_exception
- process_template_response(不常用)
- 四、CSRF_TOKEN
流程圖介紹中間件
一、什么是中間件
Django中間件類似于django的門戶,所有的請求來和響應走走必須經過中間件
中間件顧名思義,是介于request與response處理之間的一道處理過程
,相對比較輕量級,并且在全局上改變django的輸入與輸出。因為改變的是全局,所以需要謹慎實用,用不好會影響到性能
Django官方中間件的定義:
Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
中間件它的執行位置在web服務網關接口之后,在路由匹配之前執行的
二、中間件有什么用
如果你想修改請求,例如被傳送到view中的HttpRequest
對象。 或者你想修改view返回的HttpResponse
對象,這些都可以通過中間件來實現。
可能你還想在view執行之前做一些操作,這種情況就可以用 middleware來實現。
Django默認的中間件:(在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每一個元素就是一個中間件,如下)
'django中自帶的有七個中間件'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',]
1.django.middleware.security.SecurityMiddleware
做了一些安全處理的中間件。比如設置XSS防御的請求頭,比如做了http協議轉為https協議的工作等。
2.django.contrib.sessions.middleware.SessionMiddleware
session中間件。會給request添加一個處理好的session對象。
3.django.middleware.common.CommonMiddleware
通用中間件,會處理一些URL,比如baidu.com會自動的處理成www.baidu.com。
4.django.middleware.csrf.CsrfViewMiddleware
保護中間件,在提交表單的時候必須加入csrf_token,cookie中也會生成一個名叫csrftoken的值,也會在header中加入一個HTTP_X_CSRFTOKEN的值來放置CSRF攻擊。SessionMiddleware必須出現在CsrfMiddleware之前。
5.django.contrib.auth.middleware.AuthenticationMiddleware
用戶授權中間件。會給reqeust添加一個user對象的中間件。該中間件必須在sessionmiddleware后面。
6.django.contrib.messages.middleware.MessageMiddleware
消息處理中間件。為了在多個模版中可以使用我們返回給模版的變量,并且簡化操作。
7.django.middleware.clickjacking.XFrameOptionsMiddleware
防止通過瀏覽器頁面跨Frame出現clickjacking(欺騙點擊)攻擊出現。
中間件的執行順序
每一個中間件在請求來的時候或者響應的時候都具有一定的作用。
三、Django自定義中間件
Django給我們提供了創建自定義中間件的方式,通過創建自定義中間件來實現全局的功能,例如
全局用戶黑名單校驗、全局用戶訪問頻率校驗、網站全局用戶身份校驗等等。
中間件中主要方法及作用
'中間件類必須繼承自django.utils.deprecation.MiddlewareMixin類'process_request(self,request)用途:過濾請求'''1.請求來的時候會按照配置文件中注冊了的中間件,從上往下依次執行每一個中間件里面的porcess_request方法,如果沒有則直接跳過2.該方法如果返回了HttpResponse對象,那么請求不會再往后執行,原路返回'''process_view(self, request, callback, callback_args, callback_kwargs)用途:用于代碼層面的替換和過濾,這個方法可以拿到視圖函數的參數'''當路由匹配成功之后,執行視圖函數之前,自動觸發'''process_template_response(self,request,response)'''當視圖函數返回的數據對象中含有render屬性對應render函數才會觸發'''process_exception(self, request, exception)用途:用于一般用于捕獲發生的異常,并將其郵件發送給開發人員'''當視圖函數報錯之后,自動觸發'''process_response(self, request, response)'''1.響應走的時候會按照配置文件中注冊了的中間件,從下往上依次執行每一個中間件里面的process_response方法,如果沒有則直接跳過2.該方法有兩個形參request和response,并且默認情況下應該返回response3.該方法也可以自己返回HttpResponse對象,相當于貍貓換太子'''
'如果請求的過程中process_request方法直接返回了HttpResponse對象那么會原地執行同級別process_response返回后直接返回(flask則不同)'
創建自定義中間件的步驟:
1.在項目名下或者任意的應用名下創建一個文件夾2.在該文件夾內創建一個任意名稱的py文件3.在該py文件中編寫一個自定義的中間件類,并且必須繼承MiddlewareMixin4.緊接著去settings配置文件中注冊中間件
process_request與process_response方法
當用戶發起請求的時候會依次執行經過的所有中間件,這個時候的請求首先進入process_request
,最后到達views的函數中,views函數處理后,在依次穿過中間件,這個時候是process_response
,最后返回給請求者。
我們要自己定義中間件的話,需要寫一個類,并且
繼承MiddlewareMixin
from django.utils.deprecation import MiddlewareMixin
第一步:需要建立一個py文件夾來編寫我們自定義的中間件,建議在應用層下面創建。
app-------》Middleware-----》middle.py
from django.utils.deprecation import MiddlewareMixinclass MyMiddleware1(MiddlewareMixin):def process_request(self,request):print('這是第一個中間件的process_request')def process_response(self,request,response): # 響應print('這是第一個中間件的process_response')return responseclass MyMiddleware2(MiddlewareMixin):def process_request(self,request):print('這是第二個中間件的process_request')def process_response(self,request,response): # 響應print('這是第二個中間件的process_response')return response
第二步:在settings.py文件里面加入我們自定義的中間件
MIDDLEWARE = [# settings這個列表中存儲的其實就是一個個中間件的路徑'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',#下面兩個就是自定義的中間件路徑地址'app.Middleware.middle.MyMiddleware1','app.Middleware.middle.MyMiddleware2',]
第三步:定義視圖函數
'記得別忘記配置路由'def func(request):print('from func')return HttpResponse('from func')
當我們瀏覽器朝服務端發送請求,必定會經過我們剛才定義的中間件
而process_request
方法的request則是請求,response則是視圖函數返回的內容到了中間件里面,然后由中間件return出去。所以我們是可以在process_response
里面不寫return視圖函數返回的內容,自己定義內容返回。
從下圖看,正常的情況下按照綠色的路線進行執行,假設中間件1有返回值,則按照紅色的路線走,直接執行該類下的process_response方法返回,后面的其他中間件就不會執行。
也就是說中間件的process_request
方法使用了return
,那么其后面的中間件將不再執行,直接執行該中間件和其上面中間件的process_response
方法,最終將某個process_request
里面的return值返回給請求者。
由此總結:
- 中間件的process_request方法是在執行視圖函數之前執行的。
- 當配置多個中間件時,會按照MIDDLEWARE中的注冊順序,也就是列表的索引值,從前到后依次執行的。
- 不同中間件之間傳遞的request都是同一個對象
多個中間件中的process_response方法是按照MIDDLEWARE中的注冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最后執行,最后一個中間件的process_request方法最后一個執行,它的process_response方法是最先執行的。
process_view方法
該方法格式:process_view(request, view_func, view_args, view_kwargs)
process_view方法的四個參數:
- request:HTTPRequest對象
- view_func:Django即將調用的視圖函數
- view_args:將傳遞給視圖的位置參數的元組
- view_kwargs:是將傳遞給視圖的關鍵字參數的字典
view_args和view_kwargs都不包含第一個視圖函數(request)
process_view方法是在視圖函數之前,process_request方法之后執行的。
它應該返回None或一個HttpResponse對象,如果返回None,Django將繼續處理這個請求,執行任何其他中間件的process_view方法,然后在執行相應的視圖。如果它返回一個HttpResponse對象,Django不會調用適當的視圖函數。它將執行中間件的process_response方法并將應用到該HttpResponse并返回結果。
自定義中間件:
記得需要注冊自定義中間件from django.utils.deprecation import MiddlewareMixinclass Md1(MiddlewareMixin):def process_request(self,request):print('M1請求來時,校驗')def process_response(self,reqeust,response):print('M1返回數據時,對數據進行處理')return responsedef process_view(self,request,view_func,view_args,view_kwargs):print('我在只給你view函數前執行!')class Md2(MiddlewareMixin):def process_reqeust(self,request):print('M2請求來時,校驗')def process_response(self,request,response):print('M2返回數據時,對數據進行處理')return responsedef process_view(self,request,view_func,view_args,view_kwargs):pass執行結果》》》》:M1請求來時,校驗我在只給你view函數前執行!from funcM2返回數據時,對數據進行處理M1返回數據時,對數據進行處理
下圖分析上面代碼的執行過程:
當最后一個中間件的process_reqeust到達路由關系映射之后,返回到中間件1的process_view,然后依次往下,到達views函數,最后通過process_response依次返回到達用戶。
注意:process_view如果有返回值,會越過其他的process_view以及視圖函數,但是所有的process_response都還會執行。
process_exception
process_exception(self, request, exception)
該方法兩個參數:
- 一個HttpRequest對象
- 一個exception是視圖函數異常產生的Exception對象。
這個方法只有在視圖函數中出現異常了才執行,它返回的值可以是一個None也可以是一個HttpResponse對象。如果是HttpResponse對象,Django將調用模板和中間件中的process_response方法,并返回給瀏覽器,否則將默認處理異常。如果返回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件注冊順序的倒序執行。
視圖函數制造錯誤
def index(request):print('index視圖函數執行了')lis = [1,2,3]lis[4]
自定義中間件:
class Md1(MiddlewareMixin):def process_request(self,request):print("Md1請求")def process_response(self,request,response):print("Md1返回")return responsedef process_view(self, request, callback, callback_args, callback_kwargs):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返回")print(response.content)return responsedef process_view(self, request, view_func, view_args, view_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...index視圖函數執行了md2 process_exception...Md2返回b'list index out of range'Md1返回
當process_exception進行return HttpResponse后,process_response方法就會拿到其返回的數據。
當views出現錯誤時流程圖如下:
process_template_response(不常用)
該方法對視圖函數返回值有要求,必須是一個含有render方法類的對象,才會執行此方法。
process_template_response 函數是在視圖函數執行完后立即執行的
視圖
def index(request):print("這里是 index 頁面")repsponse = HttpResponse("這里是主頁面 index")def render():print("這里是 index 函數里的 render 方法")return HttpResponse("index")repsponse.render = renderreturn repsponse
自定義中間件
class Md2(MiddlewareMixin):def process_request(self,request):print("Md2請求")def process_response(self,request,response):print("Md2返回")return responsedef process_view(self, request, view_func, view_args, view_kwargs):print(view_func)print("md2 process_view...")def process_template_response(self, request, response):print("視圖函數執行完畢,且返回了render")return response執行結果》》》》:Md2請求md2 process_view...這里是 index 頁面視圖函數執行完畢,且返回了render這里是 index 函數里的 render 方法Md2返回