Django-中間件

自定義中間件

中間件能夠定義五個方法,分別是:(主要的是process_request和process_response)django

  • process_request(self,request)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值能夠是None或一個HttpResponse對象,若是是None,則繼續按照django定義的規則向後繼續執行,若是是HttpResponse對象,則直接將該對象返回給用戶。瀏覽器

自定義一箇中間件示例

from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response

中間件的方法介紹

  1. process_request

    process_request有一個參數,就是request,這個request和視圖函數中的request是同樣的。session

    它的返回值能夠是None也能夠是HttpResponse對象。返回值是None的話,按正常流程繼續走,交給下一個中間件處理,若是是HttpResponse對象,Django將不執行視圖函數,而將響應對象返回給瀏覽器。app

    咱們來看看多箇中間件時,Django是如何執行其中的process_request方法的。函數

    from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request")

    在settings.py的MIDDLEWARE配置項中註冊上述兩個自定義中間件:spa

    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', 'middlewares.MD1',  # 自定義中間件MD1
        'middlewares.MD2'  # 自定義中間件MD2
    ]

    此時,咱們訪問一個視圖,會發現終端中打印以下內容:code

    MD1裏面的 process_request MD2裏面的 process_request app01 中的 index視圖

    把MD1和MD2的位置調換一下,再訪問一個視圖,會發現終端中打印的內容以下:csrf

    MD2裏面的 process_request MD1裏面的 process_request app01 中的 index視圖

    看結果咱們知道:視圖函數仍是最後執行的,MD2比MD1先執行本身的process_request方法。中間件

    在打印一下兩個自定義中間件中process_request方法中的request參數,會發現它們是同一個對象。對象

    由此總結一下:

    1. 中間件的process_request方法是在執行視圖函數以前執行的。
    2. 當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
    3. 不一樣中間件之間傳遞的request都是同一個對象
  2. process_response

    它有兩個參數,一個是request,一個是response,request就是上述例子中同樣的對象,response是視圖函數返回的HttpResponse對象。該方法的返回值也必須是HttpResponse對象。

    給上述的M1和M2加上process_response方法:

    from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") def process_response(self, request, response): print("MD2裏面的 process_response") return response

    訪問一個視圖,看一下終端的輸出:

    MD2裏面的 process_request MD1裏面的 process_request app01 中的 index視圖 MD1裏面的 process_response MD2裏面的 process_response

    看結果可知:

    process_response方法是在視圖函數以後執行的,而且順序是MD1比MD2先執行。(此時settings.py中 MD2比MD1先註冊)

    多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一箇中間件的process_request方法最後一個執行,它的process_response方法是最早執行。

  3. process_view

    process_view(self, request, view_func, view_args, view_kwargs)

    該方法有四個參數

    request是HttpRequest對象。

    view_func是Django即將使用的視圖函數。 (它是實際的函數對象,而不是函數的名稱做爲字符串。)

    view_args是將傳遞給視圖的位置參數的列表.

    view_kwargs是將傳遞給視圖的關鍵字參數的字典。 view_args和view_kwargs都不包含第一個視圖參數(request)。

    Django會在調用視圖函數以前調用process_view方法。

    它應該返回None或一個HttpResponse對象。 若是返回None,Django將繼續處理這個請求,執行任何其餘中間件的process_view方法,而後在執行相應的視圖。 若是它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法並將應用到該HttpResponse並返回結果。

     給MD1和MD2添加process_view方法:

    from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") def process_response(self, request, response): print("MD2裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD2 中的process_view") print(view_func, view_func.__name__)

    訪問index視圖函數,看一下輸出結果:

    MD2裏面的 process_request MD1裏面的 process_request -------------------------------------------------------------------------------- MD2 中的process_view <function index at 0x000001DE68317488> index -------------------------------------------------------------------------------- MD1 中的process_view <function index at 0x000001DE68317488> index app01 中的 index視圖 MD1裏面的 process_response MD2裏面的 process_response

    process_view方法是在process_request以後,視圖函數以前執行的,執行順序按照MIDDLEWARE中的註冊順序從前到後順序執行的

  4. process_exception

    process_exception(self, request, exception)

    該方法兩個參數:

    一個HttpRequest對象

    一個exception是視圖函數異常產生的Exception對象。

    這個方法只有在視圖函數中出現異常了才執行,它返回的值能夠是一個None也能夠是一個HttpResponse對象。若是是HttpResponse對象,Django將調用模板和中間件中的process_response方法,並返回給瀏覽器,不然將默認處理異常。若是返回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件註冊順序的倒序執行。

     給MD1和MD2添加上這個方法:

    from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD1 中的process_exception") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") def process_response(self, request, response): print("MD2裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD2 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD2 中的process_exception")

    若是視圖函數中無異常,process_exception方法不執行。

    想辦法,在視圖函數中拋出一個異常:

    def index(request): print("app01 中的 index視圖") raise ValueError("呵呵") return HttpResponse("O98K")

    在MD1的process_exception中返回一個響應對象:

    class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD1 中的process_exception") return HttpResponse(str(exception))  # 返回一個響應對象

    看輸出結果:

    MD2裏面的 process_request MD1裏面的 process_request -------------------------------------------------------------------------------- MD2 中的process_view <function index at 0x0000022C09727488> index -------------------------------------------------------------------------------- MD1 中的process_view <function index at 0x0000022C09727488> index app01 中的 index視圖 呵呵 MD1 中的process_exception MD1裏面的 process_response MD2裏面的 process_response

    注意,這裏並無執行MD2的process_exception方法,由於MD1中的process_exception方法直接返回了一個響應對象。

  5. process_template_response(用的比較少)

    process_template_response(self, request, response)

    它的參數,一個HttpRequest對象,response是TemplateResponse對象(由視圖函數或者中間件產生)。

    process_template_response是在視圖函數執行完成後當即執行,可是它有一個前提條件,那就是視圖函數返回的對象有一個render()方法(或者代表該對象是一個TemplateResponse對象或等價方法)。

    class MD1(MiddlewareMixin): def process_request(self, request): print("MD1裏面的 process_request") def process_response(self, request, response): print("MD1裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD1 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD1 中的process_exception") return HttpResponse(str(exception)) def process_template_response(self, request, response): print("MD1 中的process_template_response") return response class MD2(MiddlewareMixin): def process_request(self, request): print("MD2裏面的 process_request") def process_response(self, request, response): print("MD2裏面的 process_response") return response def process_view(self, request, view_func, view_args, view_kwargs): print("-" * 80) print("MD2 中的process_view") print(view_func, view_func.__name__) def process_exception(self, request, exception): print(exception) print("MD2 中的process_exception") def process_template_response(self, request, response): print("MD2 中的process_template_response") return response

    views.py中:

    def index(request): print("app01 中的 index視圖") def render(): print("in index/render") return HttpResponse("O98K") rep = HttpResponse("OK") rep.render = render return rep

    訪問index視圖,終端輸出的結果:

    MD2裏面的 process_request MD1裏面的 process_request -------------------------------------------------------------------------------- MD2 中的process_view <function index at 0x000001C111B97488> index -------------------------------------------------------------------------------- MD1 中的process_view <function index at 0x000001C111B97488> index app01 中的 index視圖 MD1 中的process_template_response MD2 中的process_template_response in index/render MD1裏面的 process_response MD2裏面的 process_response

    從結果看出:

    視圖函數執行完以後,當即執行了中間件的process_template_response方法,順序是倒序,先執行MD1的,在執行MD2的,接着執行了視圖函數返回的HttpResponse對象的render方法,返回了一個新的HttpResponse對象,接着執行中間件的process_response方法。

中間件的執行流程

上一部分,咱們瞭解了中間件中的5個方法,它們的參數、返回值以及何時執行,如今總結一下中間件的執行流程。

請求到達中間件以後,先按照正序執行每一個註冊中間件的process_reques方法,process_request方法返回的值是None,就依次執行,若是返回的值是HttpResponse對象,再也不執行後面的process_request方法,而是執行當前對應中間件的process_response方法,將HttpResponse對象返回給瀏覽器。也就是說:若是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方法開始倒序執行。

合體:

Django請求流程圖

相關文章
相關標籤/搜索