python框架之Django(11)-中間件

介紹

在django中,中間件其實就是一個類,在一個請求到來和這個請求結束以前,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

中間件的鉤子函數

中間件提供五個鉤子函數供使用,分別是:session

  • process_request

    process_request(self,request)
    request:
    process_request有一個參數,就是request,這個request和視圖函數中的request是同一個對象。

    咱們來看看有多箇中間件時,Django是如何執行其中的process_request方法:ide

     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
    控制檯輸出:
    小結:
    一、中間件的process_request方法是在執行視圖函數以前執行的。
    二、當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
    三、不一樣中間件之間傳遞的request都是同一個對象。
    四、它的返回值能夠是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
    控制檯輸出:
    小結:
    一、process_response方法是在視圖函數以後執行的。
    二、多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的。
    三、該方法的返回值必須是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
    控制檯輸出:
    小結:
    一、process_view方法是在process_request以後,視圖函數以前執行的。
    二、它的執行順序是按照MIDDLEWARE中的註冊順序從前到後順序執行的。
    三、它應該返回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方法:spa

    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
    控制檯輸出:
    小結:
    一、這個方法只有在視圖函數中出現異常了才執行,而且是在process_response以前執行。
    二、它的執行順序是按照MIDDLEWARE中的註冊順序從前到後倒序執行的。
    三、它返回的值能夠是一個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方法:code

     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
    控制檯輸出:
    小結:
    一、中間件的process_template_response方法是在執行視圖函數以後執行的。而render函數是在process_template_response方法以後process_response方法以前執行的,且僅執行一次。
    二、它的執行順序是按照MIDDLEWARE中的註冊順序從前到後倒序執行的。
    三、該方法的返回值必須是HttpResponse對象。

中間件的執行流程

請求到達中間件以後,先按照註冊順序執行每一個註冊中間件的process_request方法,process_request方法返回的值是None,就依次執行,若是返回的值是HttpResponse對象,再也不執行後面的process_request方法,而是執行當前對應中間件的process_response方法。也就是說:以下圖,若是MIDDLEWARE中註冊了6箇中間件,執行過程當中,第3箇中間件返回了一個HttpResponse對象,那麼第四、五、6中間件的process_request和process_response方法都不執行,順序執行三、二、1中間件的process_response方法。csrf

process_request方法都執行完後,匹配路由,找到要執行的視圖函數,先不執行視圖函數,先執行中間件中的process_view方法。若是process_view方法返回None,繼續按順序執行,當全部process_view方法執行完後執行視圖函數。假如中間件3 的process_view方法返回了HttpResponse對象,則四、五、6的process_view以及視圖函數都不執行,直接從最後一箇中間件,也就是中間件6的process_response方法開始倒序執行。中間件

process_template_response和process_exception兩個方法的觸發是有條件的,執行順序也是倒序。總結全部的執行流程以下:對象

相關文章
相關標籤/搜索