Django中的中間件主要實現一些附加功能,在request被用戶handler處理前,以及用戶handler處理後生存的response進行處理。所以大部分中間件的主要功能是實現了process_request或者process_response之一,固然也能夠二者都實現,意味着該中間件涉及處處理的request和response的處理。django
在中間件的類關係中,基本類是MiddlewareMixin,其餘全部的中間件類都繼承自該類,該類僅有一個成員變量get_response,該變量在鏈接各個中間件起着很是重要的做用。該類有兩個成員函數:__init__和__call__,前者用於實現初始化,後者執行主要的功能。session
def __call__(self, request):函數
response = None插件
if hasattr(self, 'process_request'):csrf
response = self.process_request(request)中間件
if not response:blog
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類的類視圖關係圖,其餘中間件的視圖關係相似。
在工程的配置文件(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],相似於將中間件鏈表的鏈表頭保存起來,下次處理時,從該鏈表頭開始進行遍歷處理。
各個中間件的調用順序以下遞歸圖所示:
在類視圖一節中對__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,這一遞歸調用順序,決定了各個中間件處理的一些特色:
一、最早進行流程處理的中間件,其process_request()(若是存在的話)最早被執行,可是其process_response()(若是存在的話)卻最後獲得處理。
二、最後進行流程處理的中間件,其process_request()(若是存在的話)最後被執行,可是其process_response()(若是存在的話)緊接着獲得處理。
三、在中間件處理流程中,若是出現某個中間件的process_request()返回了response,這種狀況一般是處理過程當中出現了異常狀況,該中間件後續的中間件再也不參與處理,直接調用該中間件的process_response()(若是存在的話),或者直接返回。