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 -----

posted @ 2019-08-30 12:58  王先生是胖子  阅读(142)  评论(0编辑  收藏  举报