鍍金池/ 教程/ Python/ 中間件
點(diǎn)擊劫持保護(hù)
安全問題歸檔
Model 類參考
將遺留數(shù)據(jù)庫整合到Django
關(guān)聯(lián)對(duì)象參考
內(nèi)建基于類的視圖的API
聚合
Django 中的用戶認(rèn)證
django.contrib.humanize
Django管理文檔生成器
分頁
使用Django輸出CSV
加密簽名
文件儲(chǔ)存API
安全
Django中的測試
國際化和本地化
為Django編寫首個(gè)補(bǔ)丁
條件表達(dá)式
日志
模型元選項(xiàng)
部署靜態(tài)文件
執(zhí)行查詢
使用Django認(rèn)證系統(tǒng)
基于類的視圖
中間件
編寫自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫訪問優(yōu)化
錯(cuò)誤報(bào)告
基于類的內(nèi)建通用視圖
編寫自定義存儲(chǔ)系統(tǒng)
編寫你的第一個(gè) Django 程序 第3部分
編寫數(shù)據(jù)庫遷移
使用表單
編寫你的第一個(gè) Django 程序 第2部分
編寫你的第一個(gè) Django 程序 第1部分
如何使用會(huì)話
系統(tǒng)檢查框架
新手入門
信號(hào)
編寫視圖
如何使用WSGI 部署
編寫你的第一個(gè)Django應(yīng)用,第6部分
常見的網(wǎng)站應(yīng)用工具
Widgets
內(nèi)建的視圖
模型實(shí)例參考
視圖層
Django中的密碼管理
高級(jí)教程:如何編寫可重用的應(yīng)用
國際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類)
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫函數(shù)
自定義查找
使用基于類的視圖處理表單
管理操作
開發(fā)過程
編寫你的第一個(gè)Django應(yīng)用,第5部分
進(jìn)行原始的sql查詢
模型層
多數(shù)據(jù)庫
編寫你的第一個(gè) Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應(yīng)用
按需內(nèi)容處理
管理器
視圖裝飾器
驗(yàn)證器
使用Django輸出PDF
File對(duì)象
Django 的快捷函數(shù)
基于類的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

中間件

中間件是一個(gè)介入Django的請(qǐng)求和響應(yīng)的處理過程中的鉤子框架。它是一個(gè)輕量級(jí),底層的“插件”系統(tǒng),用于在全局修改Django的輸入或輸出。

中間件組件責(zé)任處理某些特殊的功能。例如,Django包含一個(gè)中間件組件,AuthenticationMiddleware ,使用會(huì)話將用戶和請(qǐng)求關(guān)聯(lián)。

這篇文檔講解了中間件如何工作,如何激活中間件,以及如何編寫自己的中間件。Django集成了一些內(nèi)置的中間件可以直接開箱即用。它們被歸檔在 內(nèi)置中間件參考.

激活中間件

要激活一個(gè)中間件組件,需要把它添加到你Django配置文件中的MIDDLEWARE_CLASSES 列表中。

在MIDDLEWARE_CLASSES中,每一個(gè)中間件組件用字符串的方式描述:一個(gè)完整的Python全路徑加上中間件的類名稱。例如,使用 django-admin startproject創(chuàng)建工程的時(shí)候生成的默認(rèn)值:

MIDDLEWARE_CLASSES = (
    '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.security.SecurityMiddleware',
)

Django的程序中,中間件不是必需的 — 只要你喜歡,MIDDLEWARE_CLASSES可以為空 — 但是強(qiáng)烈推薦你至少使用CommonMiddleware。

MIDDLEWARE_CLASSES中的順序非常重要,因?yàn)橐粋€(gè)中間件可能依賴于另外一個(gè)。例如,AuthenticationMiddleware在會(huì)話中儲(chǔ)存已認(rèn)證的用戶。所以它必須在SessionMiddleware之后運(yùn)行。一些關(guān)于Django中間件類的順序的常見提示,請(qǐng)見Middleware ordering。

鉤子和應(yīng)用順序

在請(qǐng)求階段中,調(diào)用視圖之前,Django會(huì)按照MIDDLEWARE_CLASSES中定義的順序自頂向下應(yīng)用中間件。會(huì)用到兩個(gè)鉤子:

  • process_request()
  • process_view()

在響應(yīng)階段中,調(diào)用視圖之后,中間件會(huì)按照相反的順序應(yīng)用,自底向上。會(huì)用到三個(gè)鉤子:

  • process_exception() (僅當(dāng)視圖拋出異常的時(shí)候)
  • process_template_response() (僅用于模板響應(yīng))
  • process_response()

如果你愿意的話,你可以把它想象成一顆洋蔥:每個(gè)中間件都是包裹視圖的一層“皮”。

每個(gè)鉤子的行為接下來會(huì)描述。

編寫自己的中間件

編寫自己的中間件很容易的。每個(gè)中間件組件是一個(gè)單獨(dú)的Python的class,你可以定一個(gè)或多個(gè)下面的這些方法:

process_request

process_request(request)

request是一個(gè)HttpRequest 對(duì)象。

在Django決定執(zhí)行哪個(gè)視圖(view)之前,process_request()會(huì)被每次請(qǐng)求調(diào)用。

它應(yīng)該返回一個(gè)None 或一個(gè)HttpResponse對(duì)象。如果返回 None, Django會(huì)繼續(xù)處理這個(gè)請(qǐng)求,執(zhí)行其他process_request()中間件,然后process_view()中間件顯示對(duì)應(yīng)的視圖。如果它返回一個(gè)HttpResponse對(duì)象,Django便不再會(huì)去調(diào)用其他的請(qǐng)求(request), 視圖(view)或其他中間件,或?qū)?yīng)的視圖;處理HttpResponse的中間件會(huì)處理任何返回的響應(yīng)(response)。

process_view

process_view(request, view_func, view_args, view_kwargs)

request是一個(gè)HttpRequest對(duì)象。view_func是 Django會(huì)調(diào)用的一個(gè)Python的函數(shù)。(它確實(shí)是一個(gè)函數(shù)對(duì)象,不是函數(shù)的字符名稱。) view_args是一個(gè)會(huì)被傳遞到視圖的位置參數(shù)列表,而view_kwargs 是一個(gè)會(huì)被傳遞到視圖的關(guān)鍵字參數(shù)字典。 view_args和 view_kwargs 都不包括第一個(gè)視圖參數(shù)(request)。

process_view()會(huì)在Django調(diào)用視圖(view)之前被調(diào)用。

它將返回None 或一個(gè)HttpResponse 對(duì)象。如果返回 None,將會(huì)繼續(xù)處理這個(gè)請(qǐng)求,執(zhí)行其他的process_view() 中間件,然后顯示對(duì)應(yīng)的視圖。如果返回HttpResponse對(duì)象,Django就不再會(huì)去調(diào)用其他的視圖(view),異常中間件(exception middleware)或?qū)?yīng)的視圖 ;它會(huì)把響應(yīng)中間件應(yīng)用到HttpResponse上,并返回結(jié)果。

注意

在中間件內(nèi)部,從process_request或者process_view方法中訪問request.POST或者request.REQUEST將會(huì)阻礙該中間 件之后的所有視圖無法修改request的上傳處理程序, 一般情況要避免這樣使用。

類CsrfViewMiddleware可以被認(rèn)為是個(gè)例外 ,因?yàn)樗峁┝薱srf_exempt() 和 csrf_protect()兩個(gè)允許視圖來精確控制 在哪個(gè)點(diǎn)需要開啟CSRF驗(yàn)證。

process_template_response

process_template_response(request, response)

request是一個(gè)HttpRequest對(duì)象。response是一個(gè)TemplateResponse對(duì)象(或等價(jià)的對(duì)象),由Django視圖或者中間件返回。

如果響應(yīng)的實(shí)例有render()方法,process_template_response()在視圖剛好執(zhí)行完畢之后被調(diào)用,這表明了它是一個(gè)TemplateResponse對(duì)象(或等價(jià)的對(duì)象)。

這個(gè)方法必須返回一個(gè)實(shí)現(xiàn)了render方法的響應(yīng)對(duì)象。它可以修改給定的response對(duì)象,通過修改 response.template_name和response.context_data或者它可以創(chuàng)建一個(gè)全新的 TemplateResponse或等價(jià)的對(duì)象。

你不需要顯式渲染響應(yīng) —— 一旦所有的模板響應(yīng)中間件被調(diào)用,響應(yīng)會(huì)自動(dòng)被渲染。

在一個(gè)響應(yīng)的處理期間,中間件以相反的順序運(yùn)行,這包括process_template_response()。

process_response

process_response(request, response)

request是一個(gè)HttpRequest對(duì)象。response是Django視圖或者中間件返回的HttpResponse或者StreamingHttpResponse對(duì)象。

process_response()在所有響應(yīng)返回瀏覽器之前被調(diào)用。

這個(gè)方法必須返回HttpResponse或者StreamingHttpResponse對(duì)象。它可以改變已有的response,或者創(chuàng)建并返回新的HttpResponse或StreamingHttpResponse對(duì)象。

不像 process_request()和process_view()方法,即使同一個(gè)中間件類中的process_request()和process_view()方法會(huì)因?yàn)榍懊娴囊粋€(gè)中間件返回HttpResponse而被跳過,process_response()方法總是會(huì)被調(diào)用。特別是,這意味著你的process_response()方法不能依賴于process_request()方法中的設(shè)置。

最后,記住在響應(yīng)階段中,中間件以相反的順序被應(yīng)用,自底向上。意思是定義在MIDDLEWARE_CLASSES最底下的類會(huì)最先被運(yùn)行。

處理流式響應(yīng)

不像HttpResponse,StreamingHttpResponse并沒有content屬性。所以,中間件再也不能假設(shè)所有響應(yīng)都帶有content屬性。如果它們需要訪問內(nèi)容,他們必須測試是否為流式響應(yīng),并相應(yīng)地調(diào)整自己的行為。

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

注意

我們需要假設(shè)streaming_content可能會(huì)大到在內(nèi)存中無法容納。響應(yīng)中間件可能會(huì)把它封裝在新的生成器中,但是一定不要銷毀它。封裝一般會(huì)實(shí)現(xiàn)成這樣:

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

process_exception

process_exception(request, exception)

request是一個(gè)HttpRequest對(duì)象。exception是一個(gè)被視圖中的方法拋出來的 Exception對(duì)象。

當(dāng)一個(gè)視圖拋出異常時(shí),Django會(huì)調(diào)用process_exception()來處理。process_exception()應(yīng)該返回一個(gè)None 或者一個(gè)HttpResponse對(duì)象。如果它返回一個(gè)HttpResponse對(duì)象,模型響應(yīng)和響應(yīng)中間件會(huì)被應(yīng)用,響應(yīng)結(jié)果會(huì)返回給瀏覽器。Otherwise, default exception handling kicks in.

再次提醒,在處理響應(yīng)期間,中間件的執(zhí)行順序是倒序執(zhí)行的,這包括process_exception。如果一個(gè)異常處理的中間件返回了一個(gè)響應(yīng),那這個(gè)中間件上面的中間件都將不會(huì)被調(diào)用。

__init__

大多數(shù)的中間件類都不需要一個(gè)初始化方法,因?yàn)橹虚g件的類定義僅僅是為process_*提供一個(gè)占位符。如果你確實(shí)需要一個(gè)全局的狀態(tài)那就可以通過__init__來加載。然后要銘記如下兩個(gè)警告:

Django初始化你的中間件無需任何參數(shù),因此不要定義一個(gè)有參數(shù)的__init__方法。 不像process_*每次請(qǐng)求到達(dá)都要調(diào)用__init__只會(huì)被調(diào)用一次,就是在Web服務(wù)啟動(dòng)的時(shí)候。

標(biāo)記中間件不被使用

有時(shí)在運(yùn)行時(shí)決定是否一個(gè)中間件需要被加載是很有用的。 在這種情況下,你的中間件中的 __init__方法可以拋出一個(gè)django.core.exceptions.MiddlewareNotUsed異常。Django會(huì)從中間件處理過程中移除這部分中間件,并且當(dāng)DEBUG為True的時(shí)候在django.request記錄器中記錄調(diào)試信息。

1.8中的修改:

之前 MiddlewareNotUsed異常不會(huì)被記錄。

指導(dǎo)準(zhǔn)則

  • 中間件的類不能是任何類的子類。
  • 中間件可以存在與你Python路徑中的任何位置。 Django所關(guān)心的只是被包含在MIDDLEWARE_CLASSES中的配置。
  • 將Django’s available middleware作為例子隨便看看。
  • 如果你認(rèn)為你寫的中間件組建可能會(huì)對(duì)其他人有用,那就把它共享到社區(qū)! 讓我們知道它,我們會(huì)考慮把它添加到Django中。
上一篇:編寫視圖下一篇:安全問題歸檔