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函數返回的過程中,其執行順序是,按照配置的中間鍵順序從下往上執行的。
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. 參考文章
2. https://docs.djangoproject.com/en/1.8/topics/http/middleware/#process_view