Django之Middleware中间件(***)
Django之Middleware中间件(***)
Middleware中间件,是在Django有HTTP请求时,在url去路由匹配之前的一道工序。是一道验证的功能。
在中间件中,有两个必有的方法。一个是接收到HTTP请求后要处理的。一个是处理完返回客户端时经过中间件要处理的方法。
中间件就是一个类,但是要想应用这个类,是需要进行在Settings中的中间件列表中注册的。那既然是列表,那么中间件的执行顺序是有序的。
这个类的两个必要的方法:process_request 和 process_response。
其中process_response是有return返回值的。而process_request是没有return返回值的。
如果process_request有返回值,那么HTTP请求就不会再进入路由匹配,而是直接在中间件就返回啦。
但是Django的版本不同,中间件也会有些许的区别:
Django1.10之后的版本:中间件的process_request有返回值,会直接用同中间件的process_response返回结果,而不是继续执行流程,去路由匹配views。在返回给用户应该的相应的结果。
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 -----