Django之Middleware中間件(***)前端
Middleware中間件,是在Django有HTTP請求時,在url去路由匹配以前的一道工序。是一道驗證的功能。django
在中間件中,有兩個必有的方法。一個是接收到HTTP請求後要處理的。一個是處理完返回客戶端時通過中間件要處理的方法。後端
中間件就是一個類,可是要想應用這個類,是須要進行在Settings中的中間件列表中註冊的。那既然是列表,那麼中間件的執行順序是有序的。函數
這個類的兩個必要的方法:process_request 和 process_response。url
其中process_response是有return返回值的。而process_request是沒有return返回值的。spa
若是process_request有返回值,那麼HTTP請求就不會再進入路由匹配,而是直接在中間件就返回啦。code
可是Django的版本不一樣,中間件也會有些許的區別:中間件
Django1.10以後的版本:中間件的process_request有返回值,會直接用同中間件的process_response返回結果,而不是繼續執行流程,去路由匹配views。在返回給用戶應該的相應的結果。blog
Django1.7或1.8以前的(含1.7/1.8):中間件的process_request有返回值,中間件的流程依舊會繼續執行,它會找到最後的一箇中間件,經過最後的中間件的process_response來返回,這個1.10的版本不一樣,10是同中間件的process_response直接返回,1.8以前是用最後的process_response返回。資源
中間件的編寫實例:
Settings中導入模塊並添加md的中間件:
md.py 中間件:
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_response(self,request,response): print("m1.process_response") return response class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_response(self, request, response): print("m2.process_response") return response
函數test:
def test(request): print("test") return HttpResponse("...")
中間件的執行順序,m1-m2-函數-m2-m1
當md中的中間件加上process_view函數方法:
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m1.process_view") def process_response(self,request,response): print("m1.process_response") return response class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response
它的執行順序會發生變化,他會在執行test函數並返回m1和m2的process_response以前,先去執行m1和m2的process_view。
其緣由是:
在執行完process_request的m1和m2後,又返回到了最開始的中間件,去順序執行m1和m2的process_view。
可是,在執行m1和m2的process_view這間,Django作了件路由匹配的事情,process_view的參數callback實際上是view_func的函數,好比咱們示例中的test,這個callback參數就是去匹配view視圖中test函數的路由關係啦。
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print(callback,callback_args,callback_kwargs) print("m1.process_view") def process_response(self,request,response): print("m1.process_response") return response class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response
在中間件中打印一下process_view的m1就能夠看出,在中間件執行完m2後,會再一次回到原點,去匹配對應函數的路由。
因此,在中間件中加上process_view方法後,中間件的執行順序會有變化,而這中間作的事情就是去路由中匹配對應的函數。
可是這裏發生的都是中間件中作的事情,並無觸及到真正的view函數,只有在中間件的功能的process_request都結束時,纔會真正去執行view函數。
但奇特的是:既然在process_view中就已經完成了路由的匹配,那麼在中間件中是否是也能夠直接執行view函數吶?
畢竟callback就是那個view的函數呀!!!!哈哈哈,好奇特。什麼鬼?
在process_view中有兩條路能夠走,一條是繼續往下走,執行下面的process_view,還有一條路是直接返回。
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m1.process_view") respones = callback(request,*callback_args,**callback_kwargs) return respones def process_response(self,request,response): print("m1.process_response") return response class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response
這裏的process_view執行了m1的,並無執行m2的process_view。
這裏的流程是當m2的process_view有返回值時,它是再也不執行下一個中間件的,而不是去真正的view裏執行,而是直接從最後的中間件開始返回。
因此當process_view中有返回值的時候,它會執行完全部的process_response再返回。
中間件中一共有5個方法:還有 process_template_response 和 process_exception 倆個方法。
exception是異常相關的:
正常狀況下,這個函數方法是不會被執行的,只有在有異常報錯的狀況下,纔會觸發這個方法。
from django.utils.deprecation import MiddlewareMixin class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m1.process_view") #respones = callback(request,*callback_args,**callback_kwargs) #return respones def process_response(self,request,response): print("m1.process_response") return response def process_exception(self,request,exception): print("m1.process_exception") class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response def process_exception(self,request,exception): print("m2.process_exception")
這裏的view視圖的test函數中我們讓其故意出錯
def test(request): print("test") int("asfafa") return HttpResponse("...")
其結果是:
前端報錯:
後端報錯:
他執行的順序是想執行完process_request和process_view,去view視圖處理完髮現異常後,交付的是m2和m1的process_exception。
最後纔在回到最後的中間件m2開始執行m2和m1的process_response。
在m2的process_execption中捕獲一下異常。
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m1.process_view") # respones = callback(request,*callback_args,**callback_kwargs) # return respones def process_response(self,request,response): print("m1.process_response") return response def process_exception(self,request,exception): print("m1.process_exception") class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response def process_exception(self,request,exception): print("m2.process_exception") return HttpResponse("錯誤了。。。")
頁面不在報錯,而是有return的返回:
它的輸出的結果變成了:
這裏沒有了m1的process_execption。因此,他在m2的process_execption中處理了以後,就不會在去m1的process_execption了,而是再回到m2的process_response順序處理,並返回給用戶。
最後是process_template_response 方法的應用:
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): def process_request(self,request): print("m1.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m1.process_view") # respones = callback(request,*callback_args,**callback_kwargs) # return respones def process_response(self,request,response): print("m1.process_response") return response def process_exception(self,request,exception): print("m1.process_exception") def process_template_response(self,request,response): print("m1.process_template_response") return response class M2(MiddlewareMixin): def process_request(self, request): print("m2.process_request") def process_view(self,request,callback,callback_args,callback_kwargs): print("m2.process_view") def process_response(self, request, response): print("m2.process_response") return response def process_exception(self,request,exception): print("m2.process_exception") return HttpResponse("錯誤了。。。")
結果是:
這裏沒有異常的還,將再也不有process_execption,可是也沒有process_template_response。
這裏沒有process_template_response是由於要執行這個方法是要有render的返回值。
也就是說:process_template_response的視圖函數的返回值中,若是有render方法,纔會被調用。
好比:視圖函數這樣寫:
class Foo: def __init__(self,req): self.req = req def render(self): return HttpResponse("...") def test(request): obj = Foo(request) return obj
那麼process_template_response就會被執行。由於被執行的test函數有render方法。
總結中間件:
中間件就是一個類,這個類裏有5個方法,最爲經常使用的是process_response和process_request。
中間件是嚴格按照順序有序的執行。
中間件在何時會被應用到:
當全部的請求都要統一作操做的時候,而在每一個函數裏寫是很浪費資源和時間的,因此就經過中間件的特性,當每一個請求來時都會必經的一個流程的地方作統一的處理,那就是中間件的做用,他在請求真正的去view視圖函數中處理時以前,就能夠加上咱們想要其作的事情。
說的直白一點就是:對全部的請求或一部分請求作批量處理的。
----- END -----