[譯]django middleware介紹

Middleware

Middleware是一個鑲嵌到django的request/response處理機制中的一個hooks框架。它是一個修改django全局輸入輸出的一個底層插件系統。python

每一箇中間件組件負責一些特定的功能,好比說 Django包含一個 AuthenticationMiddleware的中間間,使用sessions將用戶和請求聯繫在一塊兒( that associates users with requests using sessions.)。web

這篇文章解釋了中間件如何工做,若是激活中間件,如何編寫本身的中間件。django有不少內建的中間件,詳細內容查看內建中間件附錄。django

激活中間件

要想激活中間件,須要在settings文件中的 MIDDLEWARE_CLASSES下增長。在 MIDDLEWARE_CLASSES中,每一箇中間件以一個字符串的形勢保存。好比,下面是默認建立工程的中間件 MIDDLEWARE_CLASSES內容:瀏覽器

MIDDLEWARE_CLASSES = ['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

一個django工程的建立不須要任何一箇中間件,即若是你喜歡的話,MIDDLEWARE_CLASSES能夠爲空,可是強烈建議至少包含 CommonMiddleware這個中間件。
中間件在MIDDLEWARE_CLASSES中是有順序的,由於中間件之間有相互依賴關係。好比說AuthenticationMiddleware 在session中保存認證的用戶信息,所以,它必須在 SessionMiddleware以後,詳細的內容能夠參考Middleware orderingsession

Hooks和application的順序

在請求階段,調用views以前,django按照MIDDLEWARE_CLASSES中定義的順序從上到下調用中間件。有兩個hooks:app

  • process_request()
  • process_view()

在響應階段,調用views以後,中間件被從下到上反向調用,有三個hooks:框架

  • process_exception() (只有當view中raise一個例外時)
  • process_template_response() (只有view中返回template時)
  • process_response()

若是你喜歡,能夠把它比做洋蔥,每一箇中間件就是洋蔥的一層皮。
每一個hooks在下面描述:ide

編寫你本身的中間件

寫一個本身的中間件很簡單,每一箇中間件就是一個普通的python類,包含下面的一個或多個方法:函數

1) process_request()

process_request(request)
其中request是HttpRequest對象,process_request() 將會在每一個request被決定使用哪一個view以前調用,它會返回None或者一個HttpResponse對象。測試

  • 若是返回None,django會繼續執行其餘中間件的process_request(), 而後是process_view() ,而後是恰當的view函數。
  • 若是返回HttpResponse對象,它就直接返回了,再也不執行其餘中間件,view等。

2) process_view()

process_view(request, view_func, view_args, view_kwargs)
其中request是HttpRequest 對象, view_func是django要使用的view函數 (它是實際的函數對象,而不是函數名字的字符串) view_args是view函數的列表參數, view_kwargs是view函數的字典參數。 view_args和 view_kwargs都不須要包含request這個參數。
process_view()就在django調用view函數以前被調用。
與process_request()相同,process_request()會返回None或者一個HttpResponse對象。

  • 若是返回None,django會繼續執行其餘中間件的process_view(),而後是恰當的view函數。
  • 若是返回HttpResponse對象,它就直接返回了,再也不執行其餘中間件,view等。

Note
儘可能避免使用process_request 或者process_view 來訪問request.POST。可是 CsrfViewMiddleware中間件是一個例外,它提供 csrf_exempt() 和 csrf_protect() 兩個裝飾器來解決此問題。
Accessing request.POST inside middleware from process_request orprocess_view will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided.
The CsrfViewMiddleware class can be considered an exception, as it provides the csrf_exempt() and csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should occur.

3) process_template_response()

process_template_response(request, response)
其中request 是 HttpRequest 對象, response 是一個由django view或者中間件返回的TemplateResponse 對象。
process_template_response()在view使用render渲染一個模版對象完成以後被調用,它必須返回一個render 方法執行後的response對象,它能夠修改view中返回的 response.template_name 和 response.context_data,或者爲view返回的模板增長一個商標等等。
你不須要明確的渲染響應,當全部的template響應中間件處理完成後會被自動渲染。
帶有process_template_response()的中間件將會被自下而上反向執行。

4) process_response()

process_response(request, response)
其中request是 HttpRequest 對象, response 是一個django view或者中間件返回的 HttpResponse 或者StreamingHttpResponse對象。
process_response()在全部的響應被返回到瀏覽器以前執行。
必須返回一個 HttpResponse 或者StreamingHttpResponse 對象,它能夠修改response, 或者爲 HttpResponse 或StreamingHttpResponse增長一個商標等。
它不像 process_request() 和process_view() 方法可能會被跳過(在他以前有人返回了HttpResponse對象), process_response()方法必定會被執行。所以,你的process_response() 方法不能依賴於你的process_request()方法。
最後,記住在響應階段,中間件會被反向執行,你最後在 MIDDLEWARE_CLASSES定義的中間件將會被最早執行。

處理流式響應

不一樣於HttpResponse,StreamingHttpResponse沒有content屬性,所以中間件不能認爲全部的響應都有content 屬性,若是想要訪問content,須要測試流式響應:

if response.streaming:
    response.streaming_content = wrap_streaming_content(response.streaming_content)
else:
    response.content = alter_content(response.content)

Note
streaming_content 被假定爲太大而不能存放在內存中, 響應中間件能夠將它包裹在一個生成器中,可是必須不能消費它,一般以下所示:

def wrap_streaming_content(content):
    for chunk in content:
        yield alter_content(chunk)

5) process_exception()

process_exception(request, exception)
其中request 是 HttpRequest 對象. exception是view函數中raise的Exception對象。
Django當view函數raise一個例外時調用process_exception() 。process_exception()返回None 或者HttpResponse 對象

  • 若是返回 HttpResponse 對象,template response 和response中間件會被應用, 而後在瀏覽器中返回結果,不然,默認的例外處理將會被使用。
    再說一遍,包含process_exception的中間件將會被反向執行,若是下面的中間件返回一個response,上面的中間間將不會被執行。

6) init()

大多數處理 process_* 方法的中間件都不須要自定義構造函數,若是你確實須要有一些全局的內容須要定義也能夠使用,可是注意下面兩點:

  • Django初始化中間件不會包含任何參數,因此不能在__init__ 要求任何參數;
  • 不像process_* 方法在每次請求時調用,__init__方法只會在web server首次處理請求的時候調用。

標記中間件爲不可用

有時候在運行的時候決定哪一個中間件是否可用是十分必要的,這種狀況下你的自定義中間件__init__方法能夠 raise django.core.exceptions.MiddlewareNotUsed,django將會移除中間件,而且報一個日誌,若是DEBUG打開的話,能夠在django.request logger裏看到。(1.8以前的版本,MiddlewareNotUsed不會在日誌中體現)

7)指導意見

  • 中間件不繼承;
  • 中間件寫在哪裏都行,只須要加到MIDDLEWARE_CLASSES settings中。

來源: https://docs.djangoproject.com/en/1.9/topics/http/middleware/

相關文章
相關標籤/搜索