Django源碼解析:middleware

1. middleware簡介

Django的middleware的概念相當於SSH框架裏面的filter的概念。中間鍵的作用就是對所有的request,在request前,和在response後做一定的處理。

Django的中間鍵類型分爲五種:

  • 請求(Request)中間件->對應函數process_request
  • 視圖(View)中間件->對應函數process_view
  • 模板(Template)中間件->對應函數process_template_response
  • 響應(Response)中間件->對應函數process_response
  • 異常(Exception)中間件->對應函數process_exception

我們在自定義中間鍵的時候,至少需要實現上面的五個函數之一。

 

2. middleware中間鍵函數的執行順序和過程


(1)總述

1. 應用請求中間件,處理傳入請求.如果請求中間件方法process_request返回的response非空,則終止處理過程,執行步驟7.

2. url匹配,查找視圖函數

3. 應用視圖中間件,處理傳入請求 視圖與視圖參數.如果視圖中間件方法process_view返回的response非空,則終止處理過程,執行步驟7.

4. 調用視圖函數.

5. 如果視圖函數拋出異常 ,應用異常中間件,處理傳入請求與異常.如果異常中間件方法process_exception回的response非空,則終止處理過程.無論是否終止過程,都會跳到步驟7.

6. 如果response支持延遲渲染,應用模板中間件.(If the response supports deferred rendering, apply template response middleware and the render the response).執行步驟7.

7. 應用響應中間件,處理傳入請求與中間件返回的response.

 


(2)當Handler接受到客戶端的請求過程的處理細節過程

具體的處理函數的文件定義在django/core/handler/base.py文件之中

當handler接受到一個客戶端的請求的時候,其執行過程如下

1. 根據setting.py配置的MIDDLEWARE_CLASSES,import相應的包。然後很據裏面定義的5中類型的中間鍵,提取出來,保存在self._request_middleware,self._view_middleware ,self._template_response_middleware ,self._response_middleware ,self._exception_middleware這五個list變量中。

self._view_middleware = []
        self._template_response_middleware = []
        self._response_middleware = []
        self._exception_middleware = []

        request_middleware = []
        for middleware_path in settings.MIDDLEWARE_CLASSES:
            mw_class = import_string(middleware_path)
            try:
                # 實例化該middleware 如果不存在該類文件,則跳過
                mw_instance = mw_class()
            except MiddlewareNotUsed:
                continue

            if hasattr(mw_instance, 'process_request'):
                request_middleware.append(mw_instance.process_request)
            if hasattr(mw_instance, 'process_view'):
                self._view_middleware.append(mw_instance.process_view)

            # 倒序的插入的,因此從reponse後的middleware的函數,是從後往前執行的
            if hasattr(mw_instance, 'process_template_response'):
                self._template_response_middleware.insert(0, mw_instance.process_template_response)
            if hasattr(mw_instance, 'process_response'):
                self._response_middleware.insert(0, mw_instance.process_response)
            if hasattr(mw_instance, 'process_exception'):
                self._exception_middleware.insert(0, mw_instance.process_exception)

從上面的代碼我們也可以看出:對於配置的middleware中間鍵,其執行過程是有順序的。在request傳入的過程中,process_request和process_view函數,是按照配置的順序從上往下執行的。在response函數返回的過程中,其執行順序是,按照配置的中間鍵順序從下往上執行的。

image

2.執行request的middleware

從代碼中,我們可以看出,當middleware函數返回非None的時候,就直接跳轉到response的middleware的階段了,不再去繼續執行下面的request的middleware函數。

 # Apply request middleware
            # 遍歷前面保存的middleware裏面的request方法,並且進行執行
            for middleware_method in self._request_middleware:

                # request方法是沒有返回值的,如果有返回那麼就退出了
                response = middleware_method(request)
                if response:
                    break

3.根據請求的路徑,查找相應的處理的view

if response is None:
                # 根據reques.path_info和配置的urlconf的urls進行匹配,查找相應的處理的view
                if hasattr(request, 'urlconf'):
                    # Reset url resolver with a custom urlconf.

                    # 該request可能有自己的urlconf
                    urlconf = request.urlconf
                    urlresolvers.set_urlconf(urlconf)
                    resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)

                resolver_match = resolver.resolve(request.path_info)
                callback, callback_args, callback_kwargs = resolver_match
                request.resolver_match = resolver_match

4. 執行view的middleware

  # Apply view middleware
                # 執行view的middlerware
                for middleware_method in self._view_middleware:
                    response = middleware_method(request, callback, callback_args, callback_kwargs)
                    if response:
                        break

 

5.執行view函數,得到response。如果有異常,就執行exception的middleware

if response is None:
                # 執行view函數

                wrapped_callback = self.make_view_atomic(callback)
                try:
                    response = wrapped_callback(request, *callback_args, **callback_kwargs)

                # 如果出現異常,那麼就執行異常的middleware
                except Exception as e:
                    # If the view raised an exception, run it through exception
                    # middleware, and if the exception middleware returns a
                    # response, use that. Otherwise, reraise the exception.
                    for middleware_method in self._exception_middleware:
                        response = middleware_method(request, e)
                        if response:
                            break
                    if response is None:
                        raise

6. 執行response的middleware,得到最終的返回給客戶端的response

 # If the response supports deferred rendering, apply template
            # response middleware and then render the response
            # 如果是render類型的response,就去執行render的middleware
            if hasattr(response, 'render') and callable(response.render):
                for middleware_method in self._template_response_middleware:
                    response = middleware_method(request, response)
                response = response.render()

 

3. 參考文章

1. Django源碼解析(四) 中間件

2. https://docs.djangoproject.com/en/1.8/topics/http/middleware/#process_view

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章