<li>中間件是一個鉤子框架,它們可以介入Django 的請求和響應(yīng)處理過程。它是一個輕量級、底層的“插件”系統(tǒng),用于在全局修改Django 的輸入或輸出。
<li>每個中間件組件負(fù)責(zé)完成某個特定的功能。例如,Django 包含的一個中間件組件AuthenticationMiddleware,它使用會話將用戶和請求關(guān)聯(lián)起來。
<li>這篇文檔講解中間件如何工作、如何激活中間件以及如何編寫你自己的中間件。Django集成了一些內(nèi)置的中間件可以直接開箱即用。
在1.10中的變化
jango 1.10 版本 更名為 MIDDLEWARE(單復(fù)同形)。
激活中間件
要激活一個中間件組件,需要把它添加到Django 配置文件中MIDDLEWARE_CLASSES(新版是MIDDLEWARE中)
<pre>
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.middleware.locale.LocaleMiddleware',
'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',
]
</pre>
Django的程序中,中間件不是必需的 —— 只要你喜歡,MIDDLEWARE可以為空 —— 但是強(qiáng)烈推薦你至少使用CommonMiddleware 元組中.
MIDDLEWARE中的順序非常重要,因為一個中間件可能依賴于另外一個。例如,AuthenticationMiddleware在會話中儲存已認(rèn)證的用戶。所以它必須在SessionMiddleware之后運行。
老版本中在請求階段中,調(diào)用視圖之前,Django會按照MIDDLEWARE_CLASSES中定義的順序自頂向下應(yīng)用中間件。
會用到兩個鉤子:
process_request()
process_view()
在響應(yīng)階段中,調(diào)用視圖之后,中間件會按照相反的順序應(yīng)用,自底向上。會用到三個鉤子:
process_exception()(僅當(dāng)視圖拋出異常的時候)
process_template_response()(僅用于模板響應(yīng))
process_response()。
編寫自己的中間件
老版本
編寫自己的中間件很容易的。每個中間件組件是一個獨立的Python 類,你可以定義上面這些方法中的一個或多個。
<li>process_request
process_request(request)
request是一個HttpRequest對象。在Django決定執(zhí)行哪個視圖之前,process_request()會在每個請求上調(diào)用。它應(yīng)該返回一個None或一個HttpResponse對象。如果返回None,Django會繼續(xù)處理這個請求,執(zhí)行其它process_request()中間件,然后process_view()中間件,最后是對應(yīng)的視圖。如果它返回一個HttpResponse對象,Django 就不用再去調(diào)用其它的request、view 或exception 中間件,或?qū)?yīng)的視圖;它將對HttpResponse 運用響應(yīng)階段的中間件,并返回結(jié)果。
<li>process_view
process_view(request, view_func, view_args, view_kwargs)
request
是一個HttpRequest對象。view_func是 Django會調(diào)用的一個Python的函數(shù)。(它是一個真實的函數(shù)對象,不是函數(shù)的字符名稱。) view_args是一個會被傳遞到視圖的位置參數(shù)列表,而view_kwargs是一個會被傳遞到視圖的關(guān)鍵字參數(shù)字典。view_args和 view_kwargs都不包括第一個視圖參數(shù)(request)。
process_view()會在Django 調(diào)用視圖之前被調(diào)用。
它將返回None或一[HttpResponse對象。如果返回None,Django 將會繼續(xù)處理這個請求,執(zhí)行其它的process_view()中間件,然后調(diào)用對應(yīng)的視圖。如果返回一個HttpResponse對象,Django 就不用再去調(diào)用其它的view 或exception 中間件,或?qū)?yīng)的視圖;它將對HttpResponse 運用響應(yīng)階段的中間件,并返回結(jié)果。
Accessing request.POST inside middleware before the view runs or in process_view() will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided.
<li>process_exception
process_exception(request, exception)
request是一個HttpRequest對象。exception是一個被視圖中的方法拋出來的 Exception對象。
當(dāng)一個視圖拋出異常時,Django會調(diào)用process_exception()來處理。process_exception()應(yīng)該返回一個None 或者一HttpResponse
對象。如果它返回一個HttpResponse對象,模型響應(yīng)和響應(yīng)中間件會被應(yīng)用,響應(yīng)結(jié)果會返回給瀏覽器。否則, 默認(rèn)的異常處理機(jī)制將會被觸發(fā)。再次提醒,在處理響應(yīng)期間,中間件的執(zhí)行順序是倒序執(zhí)行的,這包括process_exception。如果一個異常處理的中間件返回了一個響應(yīng),那這個中間件上面的中間件都將不會被調(diào)用。
<li>process_template_response
process_template_response(request, response)
request是一個HttpRequest對象。response是一TemplateResponse對象(或等價的對象),由Django視圖或者中間件返回。
如果響應(yīng)的實例有render()方法,process_template_response()在視圖剛好執(zhí)行完畢之后被調(diào)用,這表明了它是一個TemplateResponse對象(或等價的對象)。這個方法必須返回一個實現(xiàn)了render方法的響應(yīng)對象。它可以修改給定的response對象,通過改 response.template_name和response.context_data或者它可以創(chuàng)建一個全新的 TemplateResponse或等價的對象。你不需要顯式渲染響應(yīng) —— 一旦所有的模板響應(yīng)中間件被調(diào)用,響應(yīng)會自動被渲染。在一個響應(yīng)的處理期間,中間件以相反的順序運行,這包括process_template_response()
<li>process_response
process_response(request, response)
request是一個HttpRequest對象。
response是Django視圖或者中間件返回的HttpResponse或者StreamingHttpResponse對象。
process_response()在所有響應(yīng)返回瀏覽器之前被調(diào)用。
這個方法必須返回HttpResponse或者StreamingHttpResponse對象。它可以改變已有的response,或者創(chuàng)建并返回新的HttpResponse或StreamingHttpResponse)對象。不像 process_request()和process_view()方法,即使同一個中間件類中的process_request()和process_view()方法會因為前面的一個中間件返回HttpResponse而被跳過,process_response()方法總是會被調(diào)用。特別是,這意味著你的process_response()方法不能依賴于process_request()方法中的設(shè)置。
最后,記住在響應(yīng)階段中,中間件以相反的順序被應(yīng)用,自底向上。意思是定義在MIDDLEWARE_CLASSES最底下的類會最先被運行。
例如
<pre>
class BookMiddleware(object):
def process_request(self, request):
print ("Middleware executed")
return None
把這個加到MIDDLEWARE_CLASSES里面,則相應(yīng)每一個請求時都會輸出Middleware executed
</pre>
<pre>
class AnotherMiddleware(object):
def process_request(self, request):
print "Another middleware executed"
在把BookMiddleware和AnotherMiddleware先后加入MIDDLEWARE_CLASSES中時,輸出:
Middleware executed
Another middleware executed
</pre>
process_response
<pre>
class AnotherMiddleware(object):
def process_request(self, request):
print "Another middleware executed"
def process_response(self, request, response):
print "AnotherMiddleware process_response executed"
return response
class BookMiddleware(object):
def process_request(self, request):
print "Middleware executed"
print request.user
#return HttpResponse("some response")
#self._start = time.time()
def process_response(self, request, response):
print "BookMiddleware process_response executed"
return response
在把BookMiddleware和AnotherMiddleware先后加入MIDDLEWARE_CLASSES中時,輸出
Middleware executed
Another middleware executed
AnotherMiddleware process_response executed
BookMiddleware process_response executed
requset和response的相反的順序
</pre>
新版中
內(nèi)置的中間件都繼承自
<pre>
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
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
__call__ 方法會先調(diào)用 self.process_request(request),接著執(zhí)行 self.get_response(request) 然后調(diào)用 self.process_response(request, response) (如果子類中定義的話)
</pre>
自定義一個新版的中間件(不繼承MiddlewareMixin)
<pre>
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
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
def process_request(self,request):
pass
def process_response(self,request,response):
#code
</pre>
或者直接繼承MiddlewareMixin實現(xiàn)相應(yīng)的方法