zoukankan      html  css  js  c++  java
  • python框架之Django(11)-中间件

    介绍

    在django中,中间件其实就是一个类,在一个请求到来和这个请求结束之前,django会根据自己的规则在合适的时机执行中间件中相应的方法。

    在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下: 

    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',
    ]

    使用

    自定义中间件

    • 创建中间件类

       1 from django.utils.deprecation import MiddlewareMixin
       2 
       3 
       4 class Middleware1(MiddlewareMixin):
       5     def process_request(self, request): print('from process_request')
       6 
       7     def process_view(self, request, callback, callback_args, callback_kwargs): print('from process_view')
       8 
       9     def process_template_response(self, request, response): print('from process_template_response')
      10 
      11     def process_exception(self, request, exception): print('from process_exception')
      12 
      13     def process_response(self, request, response):
      14         print('from process_response')
      15         return response
      中间件类
    • 注册中间件

       1 MIDDLEWARE = [
       2     'django.middleware.security.SecurityMiddleware',
       3     'django.contrib.sessions.middleware.SessionMiddleware',
       4     'django.middleware.common.CommonMiddleware',
       5     'django.middleware.csrf.CsrfViewMiddleware',
       6     'django.contrib.auth.middleware.AuthenticationMiddleware',
       7     'django.contrib.messages.middleware.MessageMiddleware',
       8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
       9     'Middleware.TestMiddleware.Middleware1'
      10 ]
      settings.py

    中间件的钩子函数

    中间件提供五个钩子函数供使用,分别是:

    • process_request

      process_request(self,request)
      request:
      process_request有一个参数,就是request,这个request和视图函数中的request是同一个对象。

      我们来看看有多个中间件时,Django是如何执行其中的process_request方法:

       1 MIDDLEWARE = [
       2     'django.middleware.security.SecurityMiddleware',
       3     'django.contrib.sessions.middleware.SessionMiddleware',
       4     'django.middleware.common.CommonMiddleware',
       5     'django.middleware.csrf.CsrfViewMiddleware',                            # 此项便是拦截CSRF请求的中间件
       6     'django.contrib.auth.middleware.AuthenticationMiddleware',
       7     'django.contrib.messages.middleware.MessageMiddleware',
       8     'django.middleware.clickjacking.XFrameOptionsMiddleware',
       9     'Middleware.TestMiddleware.Middleware1'
      10     'Middleware.TestMiddleware.Middleware2'
      11 ]
      settings.py
      1 from django.utils.deprecation import MiddlewareMixin
      2 
      3 
      4 class Middleware1(MiddlewareMixin):
      5     def process_request(self, request): print('from Middleware1.process_request')
      6 
      7 
      8 class Middleware2(MiddlewareMixin):
      9     def process_request(self, request): print('from Middleware2.process_request')
      /Middleware/TestMiddleware.py
      1 from django.shortcuts import render,HttpResponse
      2 
      3 
      4 def test(request):
      5     print('from view func')
      6     return HttpResponse('ok')
      views.py
      1 from Middleware1.process_request
      2 from Middleware2.process_request
      3 from view func
      控制台输出:
      小结:
      1、中间件的process_request方法是在执行视图函数之前执行的。
      2、当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是列表的索引值,从前到后依次执行的。
      3、不同中间件之间传递的request都是同一个对象。
      4、它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而直接将该HttpResponse对象返回给浏览器。
    • process_response

      process_response(self, request, response)
      request:
      HttpRequest对象(请求对象)。
      response:
      response是视图函数返回的HttpResponse对象。
      给上述的Middleware1和Middleware2加上process_response方法:
       1 from django.utils.deprecation import MiddlewareMixin
       2 from django.shortcuts import HttpResponse
       3 
       4 
       5 class Middleware1(MiddlewareMixin):
       6     def process_request(self, request): print('from Middleware1.process_request')
       7 
       8     def process_response(self, request, response):
       9         print('from Middleware1.process_response')
      10         return HttpResponse('ok')
      11 
      12 
      13 class Middleware2(MiddlewareMixin):
      14     def process_request(self, request): print('from Middleware2.process_request')
      15 
      16     def process_response(self, request, response):
      17         print('from Middleware2.process_response')
      18         return HttpResponse('ok')
      /Middleware/TestMiddleware.py
      from Middleware1.process_request
      from Middleware2.process_request
      from view func
      from Middleware2.process_response
      from Middleware1.process_response
      控制台输出:
      小结:
      1、process_response方法是在视图函数之后执行的。
      2、多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的。
      3、该方法的返回值必须是HttpResponse对象。
    • process_view

      process_view(self, request, view_func, view_args, view_kwargs)
      request:
      HttpRequest对象(请求对象)。
      view_func:
      请求所对应的视图函数句柄。
      view_args:
      传递给视图函数的位置参数。
      view_kwargs:
      传递给视图函数的关键字参数。

      给上述的Middleware1和Middleware2加上process_view方法:

       1 from django.utils.deprecation import MiddlewareMixin
       2 from django.shortcuts import HttpResponse
       3 
       4 
       5 class Middleware1(MiddlewareMixin):
       6     def process_request(self, request): print('from Middleware1.process_request')
       7 
       8     def process_response(self, request, response):
       9         print('from Middleware1.process_response')
      10         return HttpResponse('ok')
      11 
      12     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view')
      13 
      14 
      15 class Middleware2(MiddlewareMixin):
      16     def process_request(self, request): print('from Middleware2.process_request')
      17 
      18     def process_response(self, request, response):
      19         print('from Middleware2.process_response')
      20         return HttpResponse('ok')
      21 
      22     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view')
      /Middleware/TestMiddleware.py
      1 from Middleware1.process_request
      2 from Middleware2.process_request
      3 from Middleware1.process_view
      4 from Middleware2.process_view
      5 from view func
      6 from Middleware2.process_response
      7 from Middleware1.process_response
      控制台输出:
      小结:
      1、process_view方法是在process_request之后,视图函数之前执行的。
      2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后顺序执行的。
      3、它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续执行其他中间件的process_view方法,然后再执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用后续的视图函数。 而将直接执行中间件的process_response方法并将用该HttpResponse返回结果。
    • process_exception

      process_exception(self, request, exception)
      request:
      HttpRequest对象(请求对象)。
      exception:
      exception是视图函数产生的Exception(异常)对象。

      修改视图函数,并给上述的Middleware1和Middleware2加上process_exception方法:

      1 from django.shortcuts import render, HttpResponse
      2 
      3 
      4 def test(request):
      5     print('from view func')
      6     i = 1 / 0
      7     return HttpResponse('ok')
      views.py
       1 from django.utils.deprecation import MiddlewareMixin
       2 from django.shortcuts import HttpResponse
       3 
       4 
       5 class Middleware1(MiddlewareMixin):
       6     def process_request(self, request): print('from Middleware1.process_request')
       7 
       8     def process_response(self, request, response):
       9         print('from Middleware1.process_response')
      10         return HttpResponse('ok')
      11 
      12     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view')
      13 
      14     def process_exception(self, request, exception):
      15         print('from Middleware1.process_exception')
      16 
      17 
      18 class Middleware2(MiddlewareMixin):
      19     def process_request(self, request): print('from Middleware2.process_request')
      20 
      21     def process_response(self, request, response):
      22         print('from Middleware2.process_response')
      23         return HttpResponse('ok')
      24 
      25     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view')
      26 
      27     def process_exception(self, request, exception):
      28         print('from Middleware2.process_exception')
      /Middleware/TestMiddleware.py
      from Middleware1.process_request
      from Middleware2.process_request
      from Middleware1.process_view
      from Middleware2.process_view
      from view func
      from Middleware2.process_exception
      from Middleware1.process_exception
      Internal Server Error: ...
      ZeroDivisionError: division by zero
      from Middleware2.process_response
      from Middleware1.process_response
      控制台输出:
      小结:
      1、这个方法只有在视图函数中出现异常了才执行,并且是在process_response之前执行。
      2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后倒序执行的。
      3、它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将在直接依次调用中间件中的process_response方法。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。
    • process_template_response

      process_template_response(self, request, response)
      request:
      HttpRequest对象(请求对象)。
      response:
      response是视图函数返回的HttpResponse对象且这个对象中一定要包含名为render的函数。

      修改视图函数,并给上述的Middleware1和Middleware2加上process_template_response方法:

       1 from django.shortcuts import render, HttpResponse
       2 
       3 
       4 def test(request):
       5     print('from view func')
       6     def render():
       7         print('from render')
       8     resp = HttpResponse('ok')
       9     resp.render = render
      10     return resp
      views.py
       1 from django.utils.deprecation import MiddlewareMixin
       2 from django.shortcuts import HttpResponse
       3 
       4 
       5 class Middleware1(MiddlewareMixin):
       6     def process_request(self, request): print('from Middleware1.process_request')
       7 
       8     def process_response(self, request, response):
       9         print('from Middleware1.process_response')
      10         return HttpResponse('ok')
      11 
      12     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware1.process_view')
      13 
      14     def process_exception(self, request, exception):
      15         print('from Middleware1.process_exception')
      16 
      17     def process_template_response(self, request, response):
      18         print('from Middleware1.process_template_response')
      19         return response
      20 
      21 
      22 class Middleware2(MiddlewareMixin):
      23     def process_request(self, request): print('from Middleware2.process_request')
      24 
      25     def process_response(self, request, response):
      26         print('from Middleware2.process_response')
      27         return HttpResponse('ok')
      28 
      29     def process_view(self, request, callback, callback_args, callback_kwargs): print('from Middleware2.process_view')
      30 
      31     def process_exception(self, request, exception):
      32         print('from Middleware2.process_exception')
      33 
      34     def process_template_response(self, request, response):
      35         print('from Middleware2.process_template_response')
      36         return response
      /Middleware/TestMiddleware.py
      from Middleware1.process_request
      from Middleware2.process_request
      from Middleware1.process_view
      from Middleware2.process_view
      from view func
      from Middleware2.process_template_response
      from Middleware1.process_template_response
      from render
      from Middleware2.process_response
      from Middleware1.process_response
      控制台输出:
      小结:
      1、中间件的process_template_response方法是在执行视图函数之后执行的。而render函数是在process_template_response方法之后process_response方法之前执行的,且仅执行一次。
      2、它的执行顺序是按照MIDDLEWARE中的注册顺序从前到后倒序执行的。
      3、该方法的返回值必须是HttpResponse对象。

    中间件的执行流程

    请求到达中间件之后,先按照注册顺序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法。也就是说:如下图,如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4、5、6中间件的process_request和process_response方法都不执行,顺序执行3、2、1中间件的process_response方法。

    process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法。如果process_view方法返回None,继续按顺序执行,当所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4、5、6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

    process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

  • 相关阅读:
    高效是如何来的
    find 删除指定日期的文件
    MySQL基础教程
    grep search information
    关于进程的问题
    linux useradd 命令
    host and ip 的关系
    git cherry-pick 教程
    正则练习
    正则表达式-获取
  • 原文地址:https://www.cnblogs.com/zze46/p/9811943.html
Copyright © 2011-2022 走看看