middleware
中間件就是在目標和結果之間進行的額外處理程序,在Django中就是request和response之間進行的處理,相對來說實作起來比較簡單,但是要注意它是對全域有效的,可以在全域范圍內改變輸入和輸出結果,因此需要謹慎使用,否則不僅會造成難以定位的錯誤,而且可能會影響整體性能,
中間件有什么用
如果想要修改HttpRequest或者HttpResponse,就可以通過中間件來實作,
- 登陸認證:在中間件中加入登陸認證,所有請求就自動擁有登陸認證,如果需要放開部分路由,只需要特殊處理就可以了,
- 流量統計:可以針對一些渲染頁面統計訪問流量,
- 惡意請求攔截:統計IP請求次數,可以進行頻次限制或者封禁IP,
本身django專案就帶有很多的中間件,在setting.py里
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',
]
之前我們通過post請求發起的時候,就需要先注釋掉csrf那一個中間件,
每個中間件的功能如下,
SecurityMiddleware:為request/response提供了幾種安全改進;SessionMiddleware:開啟session會話支持;CommonMiddleware:基于APPEND_SLASH和PREPEND_WWW的設定來重寫URL,如果APPEND_SLASH設為True,并且初始URL 沒有以斜線結尾以及在URLconf 中沒找到對應定義,這時形成一個斜線結尾的新URL;CsrfViewMiddleware:添加跨站點請求偽造的保護,通過向POST表單添加一個隱藏的表單欄位,并檢查請求中是否有正確的值;AuthenticationMiddleware:在視圖函式執行前向每個接收到的user物件添加HttpRequest屬性,表示當前登錄的用戶,無它用不了request.user,MessageMiddleware:開啟基于Cookie和會話的訊息支持XFrameOptionsMiddleware:對點擊劫持的保護
除此以外, Django還提供了壓縮網站內容的GZipMiddleware,根據用戶請求語言回傳不同內容的LocaleMiddleware和給GET請求附加條件的ConditionalGetMiddleware,這些中間件都是可選的,
Django的中間件執行順序
當你在settings.py注冊中間件時一定要要考慮中間件的執行順序,中間件在request到達view之前是從上向下執行的,在view執行完后回傳response程序中是從下向上執行的,如下圖所示,舉個例子,如果你自定義的中間件有依賴于request.user,那么你自定義的中間件一定要放在AuthenticationMiddleware的后面

作業原理
HTTP Web服務器作業原理一般都是接收用戶發來的請求(request), 然后給出回應(response),Django也不例外,其一般作業方式是接收request物件和其它引數,交由視圖(view)處理,然后給出它的回應(respone)資料: 渲染過的html檔案或json格式的資料,然而在實際作業中Django并不是接收到request物件后,馬上交給視圖函式或類(view)處理,也不是在view執行后立馬給用戶回傳reponse,事實上Django最初接收的是HttpRequest物件,而不是request物件,正是中間件的作用把HttpRequest物件和user物件打包成了一個全域變數request物件,這樣你才可以View中使用request作為變數或者在模板中隨意呼叫request.user,

中間件(Middleware)在整個Django的request/response處理機制中的角色如下所示:
HttpRequest -> Middleware -> View -> Middleware -> HttpResponse
正是由于一個請求HttpRequest在傳遞給視圖View處理前要經過中間件處理,經過View處理后的回應也要經過中間件處理才能回傳給用戶,我們可以撰寫自己的中間件實作權限校驗,限制用戶請求、列印日志、改變輸出內容等多種應用場景,比如:
- 禁止特定IP地址的用戶或未登錄的用戶訪問我們的View視圖函式
- 對同一IP地址單位時間內發送的請求數量做出限制
- 在View視圖函式執行前記錄用戶的IP地址
- 在View視圖函式執行前傳遞額外的變數或引數
- 在View視圖函式執行前或執行后把特定資訊列印到log日志
- 在View視圖函式執行后對reponse資料進行修改后回傳給用戶
值得一提的是中間件對Django的輸入或輸出的改變是全域的,反之亦然,如果讓你希望對Django的輸入或輸出做出全域性的改變時,需要使用中間件,舉個例子,我們在裝飾器一文中介紹了如何使用@login_required裝飾器要求用戶必須先登錄才能訪問我們的視圖函式,試想我們有個網站絕大部分視圖函式都需要用戶登錄,每個視圖函式前面都需要加上@login_required裝飾器是比較傻的行為,借助于中間件,我們無需使用裝飾器即可全域實作:只有登錄用戶才能訪問視圖函式,匿名用戶跳轉到登錄頁面,實作原理也很簡單,在一個request到達視圖函式前,我們先對request.user是否驗證通過進行判斷,然后再進行跳轉,另外Django對POST表單中攜帶的CSRF token的全域校驗也是通過CsrfViewMiddleware這個中間件進行的,而不是通過單個裝飾器實作的,
自定義中間件

一般的中間件必須要有的兩個函式就是process_request和process_response
如果自己定義中間件,首先在app里創建一個py檔案,然后匯入一些自帶的模塊
from django.utils.deprecation import MiddlewareMixin
然后就是自定義類
class ReginaMiddleWare(MiddlewareMixin):
def process_request(self,request):
'''
:param request: 請求資訊物件
:return:
'''
print("reginaMiddleWare",request)
def process_response(self,response,request):
'''
:param response: 請求資訊物件
:param request: 視圖函式回傳的回應體
:return:
'''
print(response)
return response
第三步就是把自己寫好的中間件按照目錄位置添加到settings檔案當中
MIDDLEWARE = [
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'reginauser.reginaMiddleware.ReginaMiddleWare',
'reginauser.reginaMiddleware.IvanleeMiddleWare'
]
reginaMiddleWare <WSGIRequest: GET '/md/'>
ivanleeMiddleWare <WSGIRequest: GET '/md/'>
<WSGIRequest: GET '/md/'>
ivanleemiddleware <WSGIRequest: GET '/md/'>
reginamiddleware <WSGIRequest: GET '/md/'>
process_request功能

ip = request.META.get("REMOTE_ADDR")
if ip in ['127.0.0.1','']:
return HttpResponse("非法ip")
我們可以試一下本地地址,一旦process_request回傳的不是默認的None,則表示攔截成功,那么也不會經過IvanleeMiddleware,直接回到ReginaMiddleware的回應處原路回傳
process_response
def process_response(self,response,request):
'''
:param response: 請求資訊物件
:param request: 視圖函式回傳的回應體
:return:
'''
print("ivanleeMiddleWare_response")
respnse = response.content + "<h1>I love Regina</h1>"
return respnse
那么在回傳的時候,回應內容就是原有的helloworld和IloveRegina一起發送給請求者,
本文來自博客園,作者:ivanlee717,轉載請注明原文鏈接:https://www.cnblogs.com/ivanlee717/p/16853099.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/525926.html
標籤:其他
下一篇:在Python中理解鏈表的問題
