Django 中間件 [TOC] Django中間件可看作是包裹在django處理機制的外層,Httprequest和Httpresponse都要經中間件處理,從而起到全局鉤子的作用,可以達到一些目的:如過濾請求,預處理請求,響應修改等。 我理解,很多基於會話的應用系統,都可以設計中間件環節。如數據 ...
目錄
Django 中間件
Django中間件可看作是包裹在django處理機制的外層,Httprequest和Httpresponse都要經中間件處理,從而起到全局鉤子的作用,可以達到一些目的:如過濾請求,預處理請求,響應修改等。
我理解,很多基於會話的應用系統,都可以設計中間件環節。如資料庫系統。中間件可以起到全局鉤子的作用。django的中間件的設計就是一種遞歸順序調用,利用httprequest作為遞歸調用的參數,httpresponse作為遞歸調用的return返回。
Django提供了內置的一些中間件。思考:request對象中的user屬性中的用戶對象是怎麼來的,就是會話中間件和認證中間件處理session_id,獲取用戶對象,從而將用戶對象放入request對象中,再交與view中進行處理。request對象在中間件開發中起到了載體的作用,非常重要。
中間件框架,設計上就是嵌套調用,初始化一個中間件函數或者中間件對象;中間件函數的初始化通過一個外層的中間件工廠函數;中間件對象的初始化當然是**中間件類的__init__()函數**嘍。這兩種的初始化,工廠函數和類__init__()都需要傳入一個get_response函數,這個get_response的傳入是django引擎會帶入的,一般是初始化後的中間件列表的下一個中間件函數,或者對象,相當於就是嵌套調用遞歸下去,當最後的view函數處理完後再一層一層返回response,再進行response返回的中間件過程處理。原理設計就是嵌套遞歸返回模型(我自己起的名字,知道想表達的意思就好):
自定義中間件 - - - 大體兩種方式
中間件工廠函數方式
重點:
def simple_middleware(get_response):
# One-time configuration and initialization.
def middleware(request):
# Code to be executed for each request before
# the view (and later middleware) are called.
# 註意這裡的代碼是view之前還是之後,兩種情景的分隔就是下麵這個函數調用,這是基於遞歸調用設計的關鍵之處。
response = get_response(request)
# 下麵的就是view處理過後,可以處理httpresponse對象。
# Code to be executed for each request/response after
# the view is called.
return response
return middleware # 這是django初始化時調用中間件工廠函數,返回中間件函數。
基於中間件類方式
要點:
- 導入父類from django.utils.deprecation import MiddlewareMixin
- 自定義自己的中間件類繼承上條導入的父類
- 定義要中間件處理的django生命周期的環節處理函數:
- process_request(self,request)
- process_view(self, request, callback_view, callback_args, callback_kwargss)
- process_template_response(request, response)
- process_response(self, request, response)
- process_exception(self, request, response, except)
- 激活中間件,在settings中的MIDDLEWARE列表中放置中間件類或者中間件工廠函數。註意放置在列表中的位置,這個很重要,因為中間可能存在依賴關係(request和response就像就中間件之間傳遞個的信息的載體;如auth中間件就要放在session中間件後面)。列表中就中間件的full python path(python全路徑)字元串.
- 至於中間件程式模塊文件,可以放在python path的任何地方,建議和組件相關放一起。
# 基於類的方式一
from django.utils.deprecation import MiddlewareMixin
class MyMiddle01(MiddlewareMixin):
# 1. 定義中間件功能,具體處理整個django請求和響應的生命周期的哪一環節。
# 2. 主要有request請求到達環節;路由Urlconf後View處理前的view預處理環節;View處理過程中拋出異常的對該異常響應的處理環節(異常情況);正常情況下view返回的response環節;還有一個模版環節(不常用);
def process_request(self, request):
pass
def process_view(self, request, callback_view, callback_args, callback_kwargs):
callback_view(request, *callback_args, *callback_kwargs)
pass
def process_template_response(request, response):
pass
def process_response(self, request, response):
return response
def process_exception(request, except):
pass
# 基於類的方式二
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
# Code to be executed for each request/response after
# the view is called.
return response
def process_view():
pass
def process_exception():
pass
def process_template_response():
pass
將中間件移除
- 方式一:將中間件從配置中移除。
- 方式二:中間件初始化是拋出MiddlewareNotUsed異常即可,在初始化中間件函數或者對象時。
實例
許可權鑒別中間件
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse
import re
class RbacPermissionMiddleware(MiddlewareMixin):
"""
請求訪問許可權中間件
"""
def process_request(self, request):
"""
許可權check
:param request:
:return:
"""
req_path = request.path_info
print('用戶請求uri', req_path)
# 定義白名單url
white_list = ['/login/', '/register/']
for url in white_list:
url = '^%s$' % url
if re.match(url, req_path):
return None # 如果請求許可權是白名單中,那麼中間件返回一個None,就會進行下一個中間件處理流。
# 從session中獲取許可權url列表
p_list = request.session.get('permissions')
if not p_list:
return HttpResponse('未獲取用戶許可權信息,請登錄!')
p_flag = False
for p_url in p_list:
p_url = '^%s$' % p_url
if re.match(p_url, req_path):
p_flag = True
break
if not p_flag:
return HttpResponse('沒有訪問許可權!')
總結
- 中間件函數就類似一個view函數,參數獲取request,return返回response。只不過需要遞歸調用下一個中間件函數。(下一個中間件函數,是中間件工廠函數通過閉包傳遞給中間件函數的)
- 自定義中間件有多種形式:工廠函數,中間件類。
- 中間件註冊到django項目時,有順序性。
- 中間件會影響全局性能,畢竟所有請求都會進出都需要通過中間件。
額外的request_process()等都是只能創建在基於類的中間件,因為這些都是通過類的反射方式調用的。 或者異常觸發,或者urlconf觸發。。。
中間件函數還提供內部額外的改變請求和響應的路由路徑。如:
視圖函數正常執行時:
視圖函數拋出異常時: