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两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

  • 相关阅读:
    蓝桥网试题 java 基础练习 特殊的数字
    蓝桥网试题 java 基础练习 杨辉三角形
    蓝桥网试题 java 基础练习 查找整数
    蓝桥网试题 java 基础练习 数列特征
    蓝桥网试题 java 基础练习 字母图形
    蓝桥网试题 java 基础练习 01字串
    蓝桥网试题 java 基础练习 回文数
    蓝桥网试题 java 基础练习 特殊回文数
    Using text search in Web page with Sikuli
    each of which 用法
  • 原文地址:https://www.cnblogs.com/zze46/p/9811943.html
Copyright © 2011-2022 走看看