1. 中間件(middleware)
Django中的中間件主要實現一些附加功能,在request被用戶handler處理前,以及用戶handler處理后生存的response進行處理。因此大部分中間件的主要功能是實現了process_request或者process_response之一,當然也可以兩者都實現,意味着該中間件涉及到處理的request和response的處理。
1.1 類視圖
在中間件的類關系中,基本類是MiddlewareMixin,其他所有的中間件類都繼承自該類,該類僅有一個成員變量get_response,該變量在連接各個中間件起着非常重要的作用。該類有兩個成員函數:__init__和__call__,前者用於實現初始化,后者執行主要的功能。
def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response
其中process_request和process_response自不必多言,中間件需要實現的主要功能,通過hasattr()調用,判斷當前中間件是否具有process_request和process_response,有則調用。
不同功能的中間件,根據要完成的功能,可以擴展自己的成員變量和成員函數,通常,自定義的成員函數被process_request和process_response調用,即這些自定義的成員函數通常不對外開放。
其中,__init__成員函數有入參函數之一: get_response,這在后續的加載中間件時很重要好。
下圖是中間件SecurityMiddleware類的類視圖關系圖,其他中間件的視圖關系類似。
1.2 中間件初始化
在工程的配置文件(Project/Project/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',
]
下面來看,中間件是如何被加載和初始化的。class BaseHandler(object):中定義了load_middleware接口,具體細節如下:
handler = convert_exception_to_response(self._get_response) /*handler[0]*/
for middleware_path in reversed(settings.MIDDLEWARE):
middleware = import_string(middleware_path)
mw_instance = middleware(handler)
handler = convert_exception_to_response(mw_instance) /*handler[i]*/
self._middleware_chain = handler /*handler[end]*/
在上述例程中,開始遍歷所有中間件之前,handler(即handler[0])賦值給調用實體的_get_response成員函數。 (比如class WSGIHandler(base.BaseHandler),WSGIHandler. load_middleware()調用之后,handler[0] = WSGIHandler._get_response = BaseHandler._get_response())。遍歷所有中間件過程中,加載並初始化(middleware()調用對應着__init__成員函數)中間件,因此中間件的get_response賦值為handler[i],注意middleware()返回一個中間件類實體,接着調用調用handler = convert_exception_to_response (mw_instance),convert_exception_to_response只是對輸入函數進行了容錯封裝,在分析邏輯時,可以簡單看成輸入函數本身,因此,可以看成handler = mw_instance(request),對於一個類實體調用即調用__call__成員函數,從目前來看,大部分的中間件並沒有重載該成員函數,因此是直接調用基類的成員函數,即: MiddlewareMixin. __call__(self)。因此handler[i] = MiddlewareMixin. __call__(self)。注意該函數有一個self輸入參數,各個中間件在調用時,傳入該中間件對應的self實體,這樣self.process_request, self.process_response的調用就分別對應着不同中間夾的處理函數。load_middleware()調用之后,各個中間件通過get_response鏈接起來,這樣一個request請求到來時,可以順序通過各個中間件依次進行處理,如下圖所示:
在調用的最后,將self._middleware_chain = handler[end],類似於將中間件鏈表的鏈表頭保存起來,下次處理時,從該鏈表頭開始進行遍歷處理。
1.3 中間件使用
各個中間件的調用順序如下遞歸圖所示:
在類視圖一節中對__call__基類成員函數進行過介紹,該函數主要有先后執行的三個函數構成:process_request()、get_response()、process_response(),而get_response()通常指向下一個中間件的__call__成員函數(中間件鏈表的最后一個中間件除外,其get_response()指向handler[0]),由於各個中間件的get_response()這一特性(絕大部分指向基類__call__成員函數),使得中間件鏈表處理有點類似遞歸調用的感覺。A,B,A1,B1,A2,B2,C2,C1,C,這一遞歸調用順序,決定了各個中間件處理的一些特點:
1、最先進行流程處理的中間件,其process_request()(如果存在的話)最先被執行,但是其process_response()(如果存在的話)卻最后得到處理。
2、最后進行流程處理的中間件,其process_request()(如果存在的話)最后被執行,但是其process_response()(如果存在的話)緊接着得到處理。
3、在中間件處理流程中,如果出現某個中間件的process_request()返回了response,這種情況通常是處理過程中出現了異常情況,該中間件后續的中間件不再參與處理,直接調用該中間件的process_response()(如果存在的話),或者直接返回。