1. 程式人生 > >Django中介軟體

Django中介軟體

在有些場合,需要對Django處理的每個request都執行某段程式碼。這類程式碼可能是在view處理之前修改傳入的request,或者記錄日誌資訊以便於除錯,等等。

這類功能可以用Django的中介軟體框架來實現,該框架由切入到Djangorequest/response處理過程中的鉤子集合組成。這個輕量級低層次的plug-in系統,能用於全面的修改Django的輸入和輸出。

每個中介軟體元件都用於某個特定的功能。如果順序閱讀這本書(謹對後現代主義者表示抱歉),你可能已經多次看到中介軟體了:

§ Django會話、使用者和註冊中所有的sessionuser工具都籍由一小簇中介軟體實現(例如,由中介軟體設定

view中可見的request.sessionrequest.user)

§ Django快取機制討論的站點範圍cache實際上也是由一箇中間件實現,一旦該中介軟體發現與view相應的response已在快取中,就不再呼叫對應的view函式。

§ Django整合的子框架所介紹的flatpages,redirects,csrf等應用也都是通過中介軟體元件來完成其魔法般的功能。

這一章將深入到中介軟體及其工作機制中,並闡述如何自行編寫中介軟體。

什麼是中介軟體

中介軟體元件是遵循特定API規則的簡單Python類。在深入到該API規則的正式細節之前,先看一下下面這個非常簡單的例子。

高流量的站點通常需要將

Django部署在負載平衡proxy(參見第20)之後。這種方式將帶來一些複雜性,其一就是每個request中的遠端IP地址(request.META["REMOTE_IP"])將指向該負載平衡proxy,而不是發起這個request的實際IP。負載平衡proxy處理這個問題的方法在特殊的X-Forwarded-For中設定實際發起請求的IP

因此,需要一個小小的中介軟體來確保執行在proxy之後的站點也能夠在request.META["REMOTE_ADDR"]中得到正確的IP地址:

class SetRemoteAddrFromForwardedFor(object):

def process_request(self, request):

try:

real_ip = request.META['HTTP_X_FORWARDED_FOR']

except KeyError:

pass

else:

# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.

# Take just the first one.

real_ip = real_ip.split(",")[0]

request.META['REMOTE_ADDR'] = real_ip

一旦安裝了該中介軟體(參見下一節),每個request中的X-Forwarded-For值都會被自動插入到request.META['REMOTE_ADDR']中。這樣,Django應用就不需要關心自己是否位於負載平衡proxy之後;簡單讀取request.META['REMOTE_ADDR']的方式在是否有proxy的情形下都將正常工作。

實際上,為針對這個非常常見的情形,Django已將該中介軟體內建。它位於django.middleware.http,下一節將給出這個中介軟體相關的更多細節。

安裝中介軟體

如果按順序閱讀本書,應當已經看到涉及到中介軟體安裝的多個示例,因為前面章節的許多例子都需要某些特定的中介軟體。出於完整性考慮,下面介紹如何安裝中介軟體。

要啟用一箇中間件,只需將其新增到配置模組的MIDDLEWARE_CLASSES元組中。在MIDDLEWARE_CLASSES中,中介軟體元件用字串表示:指向中介軟體類名的完整Python路徑。例如,下面是django-admin.py startproject建立的預設MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = (

'django.middleware.common.CommonMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

'django.middleware.doc.XViewMiddleware'

)

Django專案的安裝並不強制要求任何中介軟體,如果你願意,MIDDLEWARE_CLASSES可以為空。但我們建議啟用CommonMiddleware,稍後做出解釋。

這裡中介軟體出現的順序非常重要。在requestview的處理階段,Django按照MIDDLEWARE_CLASSES中出現的順序來應用中介軟體,而在response和異常處理階段,Django則按逆序來呼叫它們。也就是說,DjangoMIDDLEWARE_CLASSES視為view函式外層的順序包裝子:在request階段按順序從上到下穿過,而在response則反過來。

中介軟體方法

現在,我們已經知道什麼是中介軟體和怎麼安裝它,下面將介紹中介軟體類中可以定義的所有方法。

Initializer: __init__(self)

在中介軟體類中,__init__()方法用於執行系統範圍的設定。

出於效能的考慮,每個已啟用的中介軟體在每個伺服器程序中只初始化次。也就是說__init__()僅在服務程序啟動的時候呼叫,而在針對單個request處理時並不執行。

對一個middleware而言,定義__init__()方法的通常原因是檢查自身的必要性。如果__init__()丟擲異常django.core.exceptions.MiddlewareNotUsed,Django將從middleware棧中移出該middleware。可以用這個機制來檢查middleware依賴的軟體是否存在、服務是否運行於除錯模式、以及任何其它環境因素。

在中介軟體中定義__init__()方法時,除了標準的self引數之外,不應定義任何其它引數。

Request預處理函式: process_request(self, request)

這個方法的呼叫時機在Django接收到request之後,但仍未解析URL以確定應當執行的view之前。Django向它傳入相應的HttpRequest物件,以便在方法中修改。

process_request()應當返回NoneHttpResponse物件.

§ 如果返回None, Django將繼續處理這個request,執行後續的中介軟體,然後呼叫相應的view.

§ 如果返回HttpResponse物件, Django將不再執行任何其它的中介軟體(而無視其種類)以及相應的view Django將立即返回該HttpResponse.

View預處理函式: process_view(self, request, view, args, kwargs)

這個方法的呼叫時機在Django執行完request預處理函式並確定待執行的view之後,但在view函式實際執行之前。

15-1列出了傳入到這個View預處理函式的引數。

表 15-1. 傳入process_view()的引數

引數

說明

request

HttpRequest物件 .

view

Django將呼叫的處理request的python函式. 這是實際的函式物件本身, 而不是字串表述的函式名。

args

將傳入view的位置引數列表,但不包括 request引數(它通常是傳 入view的第一個引數)

kwargs

將傳入view的關鍵字引數字典.

如同process_request(),process_view()應當返回NoneHttpResponse物件。

§ 如果返回None, Django將繼續處理這個request,執行後續的中介軟體,然後呼叫相應的view.

§ 如果返回HttpResponse物件, Django將不再執行任何其它的中介軟體(不論種類)以及相應的view. Django將立即返回該HttpResponse.

Response後處理函式: process_response(self, request, response)

這個方法的呼叫時機在Django執行view函式並生成response之後。這裡,該處理器就能修改response的內容;一個常見的用途是內容壓縮,如gzip所請求的HTML頁面。

這個方法的引數相當直觀:requestrequest物件,而response則是從view中返回的response物件。

不同可能返回Nonerequestview預處理函式,process_response()必須返回HttpResponse物件.這個response物件可以是傳入函式的那一個原始物件(通常已被修改),也可以是全新生成的。

Exception後處理函式: process_exception(self, request, exception)

這個方法只有在request處理過程中出了問題並且view函式丟擲了一個未捕獲的異常時才會被呼叫。這個鉤子可以用來發送錯誤通知,將現場相關資訊輸出到日誌檔案,或者甚至嘗試從錯誤中自動恢復。

這個函式的引數除了一貫的request物件之外,還包括view函式丟擲的實際的異常物件exception

process_exception()應當返回 None HttpResponse 物件.

§ 如果返回None, Django將用框架內建的異常處理機制繼續處理相應request

§ 如果返回HttpResponse物件, Django將使用該response物件,而短路框架內建的異常處理機制。

備註

Django自帶了相當數量的中介軟體類(將在隨後章節介紹),它們都是相當好的範例。閱讀這些程式碼將使你對中介軟體的強大有一個很好的認識。

內建的中介軟體

Django自帶若干內建中介軟體以處理常見問題,將從下一節開始討論。

認證支援中介軟體

中介軟體類:django.contrib.auth.middleware.AuthenticationMiddleware.

這個中介軟體啟用認證支援功能.它在每個傳入的HttpRequest物件中新增代表當前登入使用者的request.user屬性。

通用中介軟體

中介軟體類:django.middleware.common.CommonMiddleware.

這個中介軟體為完美主義者提供了一些便利:

禁止 ``DISALLOWED_USER_AGENTS``列表中所設定的user agent訪問:一旦提供,這一列表應當由已編譯的正則表示式物件組成,這些物件用於匹配傳入的request請求頭中的user-agent域。下面這個例子來自某個配置檔案片段:

import re

DISALLOWED_USER_AGENTS = (

re.compile(r'^OmniExplorer_Bot'),

re.compile(r'^Googlebot')

)

請注意import re,因為DISALLOWED_USER_AGENTS要求其值為已編譯的正則表示式(也就是re.compile()的返回值)。配置檔案是常規的python檔案,所以在其中包括Pythonimport語句不會有任何問題。

依據 ``APPEND_SLASH`` ``PREPEND_WWW``的設定執行URL重寫:如果APPEND_SLASHTrue,那些尾部沒有斜槓的URL將被重定向到添加了斜槓的相應URL,除非path的最末組成部分包含點號。因此,foo.com/bar會被重定向到foo.com/bar/,但是foo.com/bar/file.txt將以不變形式通過。

如果PREPEND_WWW True ,那些缺少先導www.URLs將會被重定向到含有先導www.的相應URL上。

這兩個選項都是為了規範化URL。其後的哲學是每個URL都應且只應當存在於一處。技術上來說,URLexample.com/barexample.com/bar/www.example.com/bar/都互不相同。搜尋引擎編目程式將把它們視為不同的URL,這將不利於該站點的搜尋引擎排名,因此這裡的最佳實踐是將URL規範化。

依據 ``USE_ETAGS``的設定處理Etag:ETags HTTP級別上按條件快取頁面的優化機制。如果USE_ETAGSTrueDjango針對每個請求以MD5演算法處理頁面內容,從而得到Etag,在此基礎上,Django將在適當情形下處理並返回Not Modified迴應(譯註:或者設定response頭中的Etag)

請注意,還有一個條件化的GET中介軟體,處理Etags並幹得更多,下面馬上就會提及。

壓縮中介軟體

中介軟體類:django.middleware.gzip.GZipMiddleware.

這個中介軟體自動為能處理gzip壓縮(包括所有的現代瀏覽器)的瀏覽器自動壓縮返回]內容。這將極大地減少Web伺服器所耗用的頻寬。代價是壓縮頁面需要一些額外的處理時間。

相對於頻寬,人們一般更青睞於速度,但是如果你的情形正好相反,儘可啟用這個中介軟體。

條件化的GET中介軟體

中介軟體類:django.middleware.http.ConditionalGetMiddleware.

這個中介軟體對條件化GET操作提供支援。如果response頭中包括Last-ModifiedETag域,並且request頭中包含If-None-MatchIf-Modified-Since域,且兩者一致,則該response將被response 304(Not modified)取代。對ETag的支援依賴於USE_ETAGS配置及事先在response頭中設定ETag域。稍前所討論的通用中介軟體可用於設定response中的ETag域。

此外,它也將刪除處理HEADrequest時所生成的response中的任何內容,並在所有requestresponse頭中設定DateContent-Length域。

反向代理支援 (X-Forwarded-For中介軟體)

中介軟體類:django.middleware.http.SetRemoteAddrFromForwardedFor.

這是我們在什麼是中介軟體這一節中所舉的例子。request.META['HTTP_X_FORWARDED_FOR']存在的前提下,它根據其值來設定request.META['REMOTE_ADDR']。在站點位於某個反向代理之後的、每個requestREMOTE_ADDR都被指向127.0.0.1的情形下,這一功能將非常有用。

紅色警告!

這個middleware驗證HTTP_X_FORWARDED_FOR的合法性。

如果站點並不位於自動設定HTTP_X_FORWARDED_FOR的反向代理之後,請不要使用這個中介軟體。否則,因為任何人都能夠偽造HTTP_X_FORWARDED_FOR值,而REMOTE_ADDR又是依據HTTP_X_FORWARDED_FOR來設定,這就意味著任何人都能夠偽造IP地址。

只有當能夠絕對信任HTTP_X_FORWARDED_FOR值得時候才能夠使用這個中介軟體。

會話支援中介軟體

中介軟體類:django.contrib.sessions.middleware.SessionMiddleware.

站點快取中介軟體

中介軟體類:django.middleware.cache.CacheMiddleware.

這個中介軟體快取Django處理的每個頁面。已在Django快取機制中詳細討論。

事務處理中介軟體

中介軟體類:django.middleware.transaction.TransactionMiddleware.

這個中介軟體將資料庫的COMMITROLLBACK繫結到request/response處理階段。如果view函式成功執行,則發出COMMIT指令。如果view函式丟擲異常,則發出ROLLBACK指令。

這個中介軟體在棧中的順序非常重要。其外層的中介軟體模組執行在Django預設的儲存-提交行為模式下。而其內層中介軟體(在棧中的其後位置出現)將置於與view函式一致的事務機制的控制下。

X-View 中介軟體

中介軟體類:django.middleware.doc.XViewMiddleware.

這個中介軟體將對來自INTERNAL_IPS所設定的內部IPHEAD請求傳送定製的X-ViewHTTP頭。Django的自動文件系統使用了這個中介軟體。

轉載請註明文章出處:http://blog.csdn.net/wolaiye320/article/details/52035451