安徽新华电脑专修学院_安徽电脑培训_安徽电脑培训学校_合肥电脑培训

當(dāng)前位置:首頁(yè) > 網(wǎng)站舊欄目 > 學(xué)習(xí)園地 > 設(shè)計(jì)軟件教程 > 翻譯www.djangobook.com之第十四章:緩存

翻譯www.djangobook.com之第十四章:緩存
2010-01-13 23:42:06  作者:  來(lái)源:
靜態(tài)網(wǎng)站的簡(jiǎn)單文件直接服務(wù)于Web,性能很好,但是動(dòng)態(tài)網(wǎng)站的一個(gè)基本的權(quán)衡是它們是動(dòng)態(tài)的,每次用戶請(qǐng)求一個(gè)頁(yè)面
Web服務(wù)器會(huì)執(zhí)行各種計(jì)算--從數(shù)據(jù)庫(kù)查詢到模板渲染到商業(yè)邏輯--來(lái)創(chuàng)建你的站點(diǎn)的訪問(wèn)者看到的頁(yè)面,從處理過(guò)度的角
度來(lái)看,這代價(jià)非常昂貴
對(duì)于大多數(shù)Web應(yīng)用,過(guò)度不是大問(wèn)題,大部分Web程序不是washingtonpost.com或者slashdot.org,它們只是簡(jiǎn)單的小的
到中等大小的流量不過(guò)如此的站點(diǎn),但是對(duì)于中等到高流量的站點(diǎn),盡可能多的去除過(guò)度就很重要,所以緩存來(lái)了
緩存就是把一個(gè)昂貴計(jì)算的結(jié)果保存起來(lái),于是你下次不需要再計(jì)算一次,這里是解釋它怎樣為動(dòng)態(tài)網(wǎng)頁(yè)工作的偽代碼:
Java代碼 復(fù)制代碼
  1. given a URL, try finding that page in the cache   
  2. if the page is in the cache:   
  3.     return the cached page   
  4. else:   
  5.     generate the page   
  6.     save the generated page in the cache (for next time)   
  7.     return the generated page  

Django帶有一個(gè)健壯的緩存系統(tǒng),它使得你可以保存動(dòng)態(tài)頁(yè)面,于是它們不需要對(duì)每個(gè)請(qǐng)求都計(jì)算,方便起見(jiàn),Django提供
了不同級(jí)別的緩存粒度,你可以緩存特殊視圖的輸出,可以只緩存很難生成的部分,也可以緩存你的整個(gè)站點(diǎn)
Django也和"上游"緩存工作的很好,例如Squid(http://www.squid-cache.org)和基于瀏覽器的緩存,這些類(lèi)型
的緩存你不直接控制,但是你可以提供關(guān)于你的站點(diǎn)哪部分應(yīng)該被緩存和怎樣緩存的線索(通過(guò)HTTP頭部)給它們

設(shè)定緩存
緩存系統(tǒng)需要一些少量的設(shè)定工作,即你必需告訴它你的緩存數(shù)據(jù)在哪里--在數(shù)據(jù)庫(kù),文件系統(tǒng)或者直接在內(nèi)存中,這是影
響你的緩存性能的重要決定,是的,一些緩存類(lèi)型要比其它的快,內(nèi)存緩存通常比文件系統(tǒng)或數(shù)據(jù)庫(kù)緩存快,因?yàn)榍罢邲](méi)有
訪問(wèn)文件系統(tǒng)或數(shù)據(jù)庫(kù)的過(guò)度
你的緩存選擇在你的settings文件的CACHE_BACKEND設(shè)置中,如果你使用緩存但沒(méi)有指定CACHE_BACKEND,Django將默認(rèn)使用
simple:///,下面解釋了CACHE_BACKEND的所有可得到的值

Memcached
目前為止Django可得到的最快的最高效的緩存類(lèi)型是基于內(nèi)存的緩存框架Memcached,它起初開(kāi)發(fā)來(lái)為L(zhǎng)iveJournal.com處理
高負(fù)荷并隨后被Danga Interactive(http://www.danga.com)開(kāi)源,它被Slashdot和Wikipedia等站點(diǎn)使用來(lái)減少
數(shù)據(jù)庫(kù)訪問(wèn)和戲劇般的增加站點(diǎn)性能
Memcached可以在http://danga.com/memcached/免費(fèi)得到,它作為后臺(tái)進(jìn)程運(yùn)行并分配一個(gè)指定數(shù)量的RAM--為
在緩存中添加,得到和刪除任意數(shù)據(jù),所有的數(shù)據(jù)直接存儲(chǔ)在內(nèi)存中,所以沒(méi)有數(shù)據(jù)庫(kù)和文件系統(tǒng)使用的過(guò)度
在安裝了Memcached本身之后,你將需要安裝Memcached Python綁定,它沒(méi)有直接和Django綁定,這些綁定在一個(gè)單獨(dú)的
Python模塊中,memcache.py,可以在http://www.djangoproject.com/thirdparty/python-memcached得到
設(shè)置CACHE_BACKEND為memcached://ip:port/來(lái)讓Django使用Memcached,這里的ip是Memcached后臺(tái)進(jìn)程的IP地址,port則是
Memcached運(yùn)行所在的端口
在這個(gè)例子中,Memcached運(yùn)行在localhost(127.0.0.1)端口11211:
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
Memcached的一個(gè)極好的特性是它在多個(gè)服務(wù)器分享緩存的能力,這意味著你可以在多臺(tái)機(jī)器上運(yùn)行Memcached進(jìn)程,程序?qū)?
會(huì)把這組機(jī)器當(dāng)作一個(gè)單獨(dú)的緩存,而不需要在每臺(tái)機(jī)器上復(fù)制緩存值,為了讓Django利用此特性,需要在CACHE_BACKEND
里包含所有的服務(wù)器地址并用分號(hào)分隔
這個(gè)例子中,緩存在運(yùn)行在172.19.26.240和172.19.26.242的IP地址和11211端口的Memcached實(shí)例間分享:
CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11211/'
這個(gè)例子中,緩存在運(yùn)行在172.19.26.240(端口11211),172.19.26.242(端口11212),172.19.26.244(端口11213)的Memcach
ed實(shí)例間分享:
CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11212;172.19.26.244:11213/'
最后關(guān)于Memcached的是基于內(nèi)存的緩存有一個(gè)重大的缺點(diǎn),因?yàn)榫彺鏀?shù)據(jù)只存儲(chǔ)在內(nèi)存中,則如果服務(wù)器死機(jī)的話數(shù)據(jù)會(huì)丟
失,顯然內(nèi)存不是為持久數(shù)據(jù)存儲(chǔ)準(zhǔn)備的,Django沒(méi)有一個(gè)緩存后端是用來(lái)做持久存儲(chǔ)的,它們都是緩存方案,而不是存儲(chǔ)
但是我們?cè)谶@里指出是因?yàn)榛趦?nèi)存的緩存特別的短暫

數(shù)據(jù)庫(kù)緩存
在你的數(shù)據(jù)庫(kù)創(chuàng)建緩存表并在表里指出Django的緩存系統(tǒng)來(lái)使用數(shù)據(jù)庫(kù)表作為緩存后端,首先運(yùn)行這個(gè)命令創(chuàng)建緩存表:
python manage.py createcachetable [cache_table_name]
這里的[cache_table_name]是要?jiǎng)?chuàng)建的數(shù)據(jù)庫(kù)表名,名字可以是任何你想要的,只要它是合法的在你的數(shù)據(jù)庫(kù)中沒(méi)有被使用
這個(gè)命令在你的數(shù)據(jù)庫(kù)創(chuàng)建一個(gè)遵循Django的數(shù)據(jù)庫(kù)緩存系統(tǒng)期望形式的單獨(dú)的表
一旦你創(chuàng)建了數(shù)據(jù)庫(kù)表,設(shè)置你的CACHE_BACKEND設(shè)置為"db://tablename",這里的tablename是數(shù)據(jù)庫(kù)表的名字,在這個(gè)例
子中,緩存表名為my_cache_table:
CACHE_BACKEND = 'db://my_cache_table'
數(shù)據(jù)庫(kù)緩存后端使用你的settings文件指定的同一數(shù)據(jù)庫(kù),你不能為你的緩存表使用不同的數(shù)據(jù)庫(kù)后端

文件系統(tǒng)緩存
使用"file://"緩存類(lèi)型作為CACHE_BACKEND并指定存儲(chǔ)緩存數(shù)據(jù)的文件系統(tǒng)目錄來(lái)在文件系統(tǒng)存儲(chǔ)緩存條目
例如,使用下面的設(shè)置來(lái)在/var/tmp/django_cache存儲(chǔ)緩存數(shù)據(jù):
CACHE_BACKEND = 'file:///var/tmp/django_cache'
注意例子中開(kāi)頭有三個(gè)前斜線,前兩個(gè)是file://,第三個(gè)是目錄路徑的第一個(gè)字符,/var/tmp/django_cache,如果你使用
Windows,把盤(pán)符字母放在file://后面,像這樣:file://c:/foo/bar
目錄路徑應(yīng)該是絕對(duì)路徑,即應(yīng)該以你的文件系統(tǒng)的根開(kāi)始,你在設(shè)置的結(jié)尾放置斜線與否無(wú)關(guān)緊要
確認(rèn)該設(shè)置指向的目錄存在并且你的Web服務(wù)器運(yùn)行的系統(tǒng)的用戶可以讀寫(xiě)該目錄,繼續(xù)上面的例子,如果你的服務(wù)器以用戶
apache運(yùn)行,確認(rèn)/var/tmp/django_cache存在并且用戶apache可以讀寫(xiě)/var/tmp/django_cache目錄
每個(gè)緩存值將被存儲(chǔ)為單獨(dú)的文件,其內(nèi)容是Python的pickle模塊以序列化("pickled")形式保存的緩存數(shù)據(jù),每個(gè)文件的
文件名是緩存鍵,并escape為安全的文件系統(tǒng)使用

本地存儲(chǔ)器緩存
如果你想要內(nèi)存緩存的速度優(yōu)勢(shì)但沒(méi)有能力運(yùn)行Memcached,可以考慮使用本地存儲(chǔ)器緩存后端,該緩存是多線程和線程安全
的,但是由于其簡(jiǎn)單的鎖和內(nèi)存分配策略它沒(méi)有Memcached高效
設(shè)置CACHE_BACKEND為'locmem:///'來(lái)使用它,例如:
CACHE_BACKEND = 'locmem:///'

簡(jiǎn)單緩存(開(kāi)發(fā)用)
'simple:///'是一個(gè)簡(jiǎn)單,單線程的內(nèi)存緩存,它只在程序中保存緩存數(shù)據(jù),這意味著它只能在開(kāi)發(fā)或測(cè)試環(huán)境下使用,如:
CACHE_BACKEND = 'simple:///'

假緩存(開(kāi)發(fā)用)
最后,Django帶有一個(gè)"假"緩存,它事實(shí)上不緩存--它只是實(shí)現(xiàn)了緩存接口但不做任何事情
如果你有一個(gè)產(chǎn)品站點(diǎn),站點(diǎn)在不同的地方使用重型緩存但開(kāi)發(fā)和測(cè)試環(huán)境中你不想使用緩存,則它是很有用的,這種情況
下,在settings文件中設(shè)置CACHE_BACKEND為'dummy:///'來(lái)做開(kāi)發(fā)環(huán)境,這樣你的開(kāi)發(fā)環(huán)境就不會(huì)使用緩存但你的產(chǎn)品環(huán)境
仍然會(huì)使用,例如:
CACHE_BACKEND = 'dummy:///'

CACHE_BACKEND參數(shù)
每個(gè)緩存后端都可能使用參數(shù),它們?cè)贑ACHE_BACKEND設(shè)置中以查詢字符串形式給出,合法的參數(shù)為:
1,timeout--緩存默認(rèn)的超時(shí)限定,以秒為單位,默認(rèn)為300秒(5分鐘)
2,max_entries--簡(jiǎn)單后端,本地存儲(chǔ)器后端和數(shù)據(jù)庫(kù)后端緩存在舊值清楚前允許的最大的條目,默認(rèn)為300
3,cull_percentage--當(dāng)?shù)竭_(dá)max_entries時(shí)選擇的條目的比率,準(zhǔn)確的比率是1/cull_percentage,所以設(shè)置cull_percenta
ge=2則當(dāng)max_entries到達(dá)時(shí)會(huì)選擇1/2的條目
cull_percentage=0表示當(dāng)?shù)竭_(dá)max_entries時(shí)條目緩存將被清除,這以更多的緩存缺失為代價(jià)讓選擇更快,默認(rèn)值為3
這個(gè)例子中,timeout設(shè)置為60:
CACHE_BACKEND = "locmem:///?timeout=60"
這個(gè)例子中,timeout為30并且max_entries為400:
CACHE_BACKEND = "locmem:///?timeout=30&max_entries=400"
不合法的參數(shù)被靜靜的忽略,作為已知參數(shù)的非法值

整站緩存
一旦你指定了CACHE_BACKEND,使用緩存的最簡(jiǎn)單的方式是緩存你的整個(gè)站點(diǎn),這意味著每個(gè)沒(méi)有GET或POST參數(shù)的頁(yè)面第一
次請(qǐng)求時(shí)都會(huì)緩存一段特有的時(shí)間
把'django.middleware.cache.CacheMiddleware'添加到你的MIDDLEWARE_CLASSES設(shè)置中來(lái)激活整站緩存,例如:
Java代碼 復(fù)制代碼
  1. MIDDLEWARE_CLASSES = (   
  2.     'django.middleware.cache.CacheMiddleware',   
  3.     'django.middleware.common.CommonMiddleware',   
  4. )  

(MIDDLEWARE_CLASSES的順序有關(guān)系,參考下面的"MIDDLEWARE_CLASSES的順序")
然后,在你的Django settings文件中添加下列必需設(shè)置:
1,CACHE_MIDDLEWARE_SECONDS--每個(gè)頁(yè)面應(yīng)該被緩存的秒數(shù)
2,CACHE_MIDDLEWARE_KEY_PREFIX--如果在同一Django安裝的多個(gè)站點(diǎn)分享緩存,設(shè)置它為站點(diǎn)名,或者其它唯一代表當(dāng)前
Django實(shí)例的字符串來(lái)防止鍵沖突,如果你不在意則可以使用空字符串
緩存中間件緩存每個(gè)沒(méi)有GET或者POST參數(shù)的頁(yè)面,即如果用戶請(qǐng)求頁(yè)面并在查詢字符串里傳遞GET參數(shù)或者POST參數(shù),中間
件將不會(huì)嘗試得到緩存版本的頁(yè)面,如果你打算使用整站緩存,設(shè)計(jì)你的程序時(shí)牢記這點(diǎn),例如,不要使用擁有查詢字符串
的URLs,除非那些頁(yè)面可以不緩存
緩存中間件支持另一個(gè)設(shè)置,CACHE_MIDDLEWARE_ANONYMOUS_ONLY,如果你定義了這個(gè)設(shè)置,并且值設(shè)為T(mén)rue,則緩存中間件
將只緩存匿名請(qǐng)求,即那些沒(méi)有登錄的用戶的請(qǐng)求,這是對(duì)用戶特有的頁(yè)面禁止緩存的簡(jiǎn)單和有效的方式,如Django的admin
界面,注意如果你使用CACHE_MIDDLEWARE_ANONYMOUS_ONLY,你應(yīng)該確認(rèn)你已經(jīng)激活了AuthenticationMiddleware并且它在
你的MIDDLEWARE_CLASSES中的CacheMiddleware之前
最后,注意CacheMiddleware自動(dòng)為每個(gè)HttpResponse設(shè)置一些頭部:
1,當(dāng)一個(gè)新(沒(méi)緩存的)版本的頁(yè)面被請(qǐng)求時(shí)設(shè)置Last-Modified頭部為當(dāng)前日期/時(shí)間
2,設(shè)置Expires頭部為當(dāng)前日期/時(shí)間加上定義的CACHE_MIDDLEWARE_SECONDS
3,設(shè)置Cache-Control頭部來(lái)給頁(yè)面一個(gè)最大的時(shí)間--再一次,根據(jù)CACHE_MIDDLEWARE_SECONDS設(shè)置

視圖緩存
一個(gè)更細(xì)粒度的使用緩存框架的方式是緩存單獨(dú)視圖的輸出,它和整站緩存有一樣的效果(包括忽略有GET和POST參數(shù)的請(qǐng)求)
它適合任何你指定的視圖,而不是整個(gè)站點(diǎn)
通過(guò)使用一個(gè)裝飾器--一個(gè)改變你的視圖方法的行為來(lái)使用緩存的封裝器來(lái)使用視圖緩存,視圖緩存裝飾器叫cache_page
它位于django.views.decorators.cache模塊,例如:
Java代碼 復(fù)制代碼
  1. from django.views.decorators.cache import cache_page   
  2.   
  3. def my_view(request, param):   
  4.     # ...   
  5. my_view = cache_page(my_view, 60 * 15)  

如果你使用Python2.4或更高,你可以使用裝飾器語(yǔ)法,這個(gè)例子是相同的:
Java代碼 復(fù)制代碼
  1. from django.views.decorators.cache import cache_page   
  2.   
  3. @cache_page(60 * 15)   
  4. def my_view(request, param):   
  5.     # ...  

cache_page使用一個(gè)單獨(dú)的參數(shù):緩存超時(shí),以秒為單位,在上面的例子中,my_view()視圖的結(jié)果將被緩存15分鐘(注意我們
為了可讀性把它寫(xiě)成了60 * 15,等于900,即15分鐘乘以每分鐘60秒)
類(lèi)似于整站緩存,視圖緩存和URL有關(guān),如果多個(gè)URLs指向同一視圖,則每個(gè)URL將被單獨(dú)緩存,繼續(xù)my_view例子,如果你的
URL配置像下面這樣:
Java代碼 復(fù)制代碼
  1. urlpatterns = ('',   
  2.     (r'^foo/(\d{1,2})/$', my_view),   
  3. )  

則對(duì)/foo/1/和/foo/23/的請(qǐng)求將像你期望的那樣被單獨(dú)緩存,但是一旦一個(gè)特別的URL(例如/foo/23/)被請(qǐng)求,則該URL后續(xù)
的請(qǐng)求將使用緩存

在URL配置指定視圖緩存
上面的例子硬編碼了視圖被緩存的事實(shí),因?yàn)閏ache_page在適當(dāng)?shù)奈恢酶淖兞薽y_view視圖,這種方式耦合了你的視圖和緩存
系統(tǒng),在一些方面這是不理想的,例如,你可能想重用視圖方法到另一個(gè)很少緩存的站點(diǎn),或者你可能想發(fā)布視圖給那些可
能想不用緩存來(lái)使用它們的人,這些問(wèn)題的解決方案是在URL配置里指定視圖緩存而不是在視圖方法本身附近
這很容易做到,當(dāng)你在URL配置里引用它的時(shí)候簡(jiǎn)單的用cache_page包裝視圖方法,這里是上面舊的URL配置:
Java代碼 復(fù)制代碼
  1. urlpatterns = ('',   
  2.     (r'^foo/(\d{1,2})/$', my_view),   
  3. )  

這里是同樣的東西,但用cache_page包裝了my_view:
Java代碼 復(fù)制代碼
  1. from django.views.decorators.cache import cache_page   
  2.   
  3. urlpatterns = ('',   
  4.     (r'^foo/(\d{1,2})/$', cache_page(my_view, 60 * 15)),   
  5. )  

如果你使用這種方式,別忘了在你的URL配置里import cache_page

低級(jí)緩存API
有時(shí)候,緩存完整渲染的頁(yè)面不會(huì)讓你收獲很多,事實(shí)上,這有點(diǎn)不方便,例如你的站點(diǎn)包括一個(gè)結(jié)果依賴于一些昂貴查詢
的結(jié)果的視圖,而且結(jié)果在一段時(shí)間后會(huì)更改,這種情況下,使用整站緩存或視圖緩存策略提供的全頁(yè)面緩存就不是很理想
因?yàn)槟悴幌刖彺嬲麄(gè)結(jié)果(既然有些數(shù)據(jù)頻繁更改的話),但是你仍然想緩存很少更改的結(jié)果
對(duì)于這種情況,Django暴露了一個(gè)簡(jiǎn)單低級(jí)的緩存API,它位于django.core.cache,你可以使用任何粒度的低級(jí)緩存API來(lái)
在緩存中存儲(chǔ)對(duì)象,你可以緩存任何可以被安全"pickled"的Python對(duì)象--字符串,字典,模型對(duì)象列表等等(大部分通常的
Python對(duì)象都可以被pickled,參考Python文檔得到更多關(guān)于pickling的信息)
這里是怎樣import它:
Java代碼 復(fù)制代碼
  1. >>> from django.core.cache import cache  

基本接口為set(key, value, timeout_seconds)和get(key):
Java代碼 復(fù)制代碼
  1. >>> cache.set('my_key''hello, world!'30)   
  2. >>> cache.get('my_key')   
  3. 'hello, world!'  

timeout_seconds參數(shù)可選并且默認(rèn)為上面解釋的CACHE_BACKEND設(shè)置中的timeout參數(shù)
如果緩存中對(duì)象不存在,或者緩存后端不可得到,則cache.get()返回None:
Java代碼 復(fù)制代碼
  1. # Wait 30 seconds for 'my_key' to expire...   
  2.   
  3. >>> cache.get('my_key')   
  4. None   
  5.   
  6. >>> cache.get('some_unset_key')   
  7. None  

我們建議不要在緩存中存儲(chǔ)字面上的None,因?yàn)槟悴荒軈^(qū)別你存儲(chǔ)的None值和通過(guò)返回None值表示的緩存缺失
cache.get()可以使用一個(gè)default參數(shù),它指定了如果對(duì)象在緩存中不存在時(shí)的返回值:
Java代碼 復(fù)制代碼
  1. >>> cache.get('my_key''has expired')   
  2. 'has expired'  

使用cache.get_many()來(lái)一次獲得多個(gè)緩存值,對(duì)于給定的緩存后端,如果可能,get_many()將只訪問(wèn)緩存一次,而不是對(duì)
每個(gè)緩存鍵訪問(wèn)一次,get_many()返回一個(gè)包含所有你請(qǐng)求的在緩存中存在并沒(méi)有過(guò)期的鍵的字典:
Java代碼 復(fù)制代碼
  1. >>> cache.set('a'1)   
  2. >>> cache.set('b'2)   
  3. >>> cache.set('c'3)   
  4. >>> cache.get_many(['a''b''c'])   
  5. {'a'1'b'2'c'3}  

如果緩存鍵不存在或者已過(guò)期,它將不包含在這個(gè)字典中,繼續(xù)例子:
Java代碼 復(fù)制代碼
  1. >>> cache.get_many(['a''b''c''d'])   
  2. {'a'1'b'2'c'3}  

最后,你可以用cache.delete()顯示的刪除鍵,這是清除緩存中特殊對(duì)象的簡(jiǎn)易方式:
Java代碼 復(fù)制代碼
  1. >>> cache.delete('a')  

cache.delete()沒(méi)有返回值,并且它同給定緩存鍵和對(duì)應(yīng)值存在與否的工作方式一樣

上游緩存
到目前為止,本章集中關(guān)注緩存你自己的數(shù)據(jù),但是另一種類(lèi)型的緩存也和Web開(kāi)發(fā)相關(guān):通過(guò)"上游"緩存來(lái)執(zhí)行緩存,這些
緩存是在請(qǐng)求到達(dá)你的Web站點(diǎn)之前為用戶緩存頁(yè)面的系統(tǒng)
這里是一些上游緩存的例子:
1,你的ISP可能緩某些頁(yè)面,所以如果你請(qǐng)求example.com的一個(gè)頁(yè)面,你的ISP將不直接訪問(wèn)example.com而發(fā)送給你那個(gè)
頁(yè)面,example.com的維護(hù)者不知道這個(gè)緩存,ISP位于example.com和你的Web瀏覽器之間透明的處理所有的緩存
2,你的Django網(wǎng)站可能在一個(gè)代理緩存后面,例如Squid(http://www.squid-cache.org),它為性能而緩存頁(yè)面
這種情況下,每個(gè)請(qǐng)求首先被代理處理,然后如果需要的話才被發(fā)送到你的程序
3,你的Web瀏覽器也緩存頁(yè)面,如果一個(gè)Web頁(yè)面發(fā)送適當(dāng)?shù)念^部,你的瀏覽器將為后面對(duì)該頁(yè)面的請(qǐng)求使用本地緩存拷貝
而不是再一次連接網(wǎng)頁(yè)來(lái)看它是否更改
上游緩存是很好的功效推進(jìn),但是它有一個(gè)危險(xiǎn),許多網(wǎng)頁(yè)的內(nèi)容基于認(rèn)證和一些其它變量而不同,并且完全基于URL來(lái)盲目
的保存頁(yè)面的緩存系統(tǒng)可能暴露不正確的或者敏感數(shù)據(jù)給后面訪問(wèn)那些頁(yè)面的訪問(wèn)者
例如,你操作一個(gè)Web e-mail系統(tǒng),"收件箱"頁(yè)面的內(nèi)容顯然依賴于登錄的用戶,如果ISP盲目的緩存你的站點(diǎn),則第一個(gè)
通過(guò)ISP登錄的用戶將會(huì)使他的用戶專有的收件箱頁(yè)面緩存給后面訪問(wèn)該站點(diǎn)的訪問(wèn)者,這不cool
幸運(yùn)的是,HTTP提供了該問(wèn)題的解決方案,存在一些HTTP頭部來(lái)告知上游緩存根據(jù)指派的變量顯示不同的緩存內(nèi)容,以及告
訴緩存機(jī)制不要緩存特殊的頁(yè)面

使用Vary頭部
這些頭部中的一個(gè)為Vary,它定義了當(dāng)緩存機(jī)制構(gòu)建它的緩存鍵時(shí)應(yīng)該考慮哪個(gè)請(qǐng)求頭部,例如,如果一個(gè)網(wǎng)頁(yè)的內(nèi)容依賴
于用戶的語(yǔ)言選擇,則這個(gè)頁(yè)面稱為"根據(jù)語(yǔ)言而不同"
Django的緩存系統(tǒng)默認(rèn)使用請(qǐng)求路徑來(lái)創(chuàng)建它的緩存鍵,例如"/stories/2005/jun/23/bank_robbed/",這意味著對(duì)該URL的
每個(gè)請(qǐng)求將使用同樣的緩存版本,不管user-agent是否不同,如cookies或者語(yǔ)言選擇等等,盡管如此,如果頁(yè)面根據(jù)請(qǐng)求
頭部的一些不同來(lái)輸出不同的內(nèi)容--如cookie,語(yǔ)言,或user-agent--你將需要使用Vary頭部來(lái)告訴緩存機(jī)制頁(yè)面輸出依賴
于那些東西,像這樣使用方便的vary_on_headers視圖裝飾器來(lái)在Django中做這個(gè):
Java代碼 復(fù)制代碼
  1. from django.views.decorators.vary import vary_on_headers   
  2.   
  3. # Python 2.3 syntax.   
  4. def my_view(request):   
  5.     # ...   
  6. my_view = vary_on_headers(my_view, 'User-Agent')   
  7.   
  8. # Python 2.4+ decorator syntax.   
  9. @vary_on_headers('User-Agent')   
  10. def my_view(request):   
  11.     # ...  

這種情況下,緩存機(jī)制(例如Django自己的緩存中間件)將對(duì)每個(gè)唯一的user-agent緩存單獨(dú)版本的頁(yè)面
使用vary_on_headers裝飾器而不是手動(dòng)設(shè)置Vary頭部(使用類(lèi)似于response['Vary'] = 'user-agent')的優(yōu)勢(shì)是裝飾器添加
到Vary頭部(可能已經(jīng)存在)而不是從零開(kāi)始設(shè)置它并潛在的覆蓋已經(jīng)在那里的東西
你可以傳遞多個(gè)頭部到vary_on_headers():
Java代碼 復(fù)制代碼
  1. @vary_on_headers('User-Agent''Cookie')   
  2. def my_view(request):   
  3.     # ...  

這告訴上游緩存對(duì)兩者而不同,即對(duì)每個(gè)user-agent和cookie的結(jié)合得到它自己的緩存值,例如,使用user-agent為Mozilla
和cookie值foo=bar的請(qǐng)求將被認(rèn)為和user-agent為Mozilla和cookie值foo=ham的請(qǐng)求不同
因?yàn)閷?duì)cookie而不同是如此常見(jiàn)的情形,有一個(gè)vary_on_cookie裝飾器,這兩個(gè)視圖是相等的:
Java代碼 復(fù)制代碼
  1. @vary_on_cookie  
  2. def my_view(request):   
  3.     # ...   
  4.   
  5. @vary_on_headers('Cookie')   
  6. def my_view(request):   
  7.     # ...  

你傳遞給vary_on_headers的頭部是大小寫(xiě)不敏感的,"User-Agent"和"user-agent"一樣
你也可以直接使用輔助方法django.utils.cache.patch_vary_headers,這個(gè)方法設(shè)置或添加到Vary頭部,例如:
Java代碼 復(fù)制代碼
  1. from django.utils.cache import patch_vary_headers   
  2.   
  3. def my_view(request):   
  4.     # ...   
  5.     response = render_to_response('template_name', context)   
  6.     patch_vary_headers(response, ['Cookie'])   
  7.     return response  

patch_vary_headers使用HttpResponse實(shí)例作為它的第一個(gè)參數(shù),一個(gè)大小寫(xiě)不敏感的頭部名的列表/元組作為它的第二個(gè)
參數(shù)

控制緩存:使用其它頭部
另一個(gè)緩存的問(wèn)題是數(shù)據(jù)的私有性和數(shù)據(jù)應(yīng)該存儲(chǔ)在級(jí)聯(lián)緩存的什么位置,用戶通常面對(duì)兩種類(lèi)型的緩存:它自己的瀏覽器
緩存(私有緩存)和他的提供者的緩存(公眾緩存),公眾緩存被多個(gè)用戶使用并且被其它的一些人控制,這產(chǎn)生了敏感數(shù)據(jù)的
問(wèn)題:你不想讓你的銀行帳號(hào)存儲(chǔ)在公眾緩存中,所以Web程序需要一種告訴緩存那些數(shù)據(jù)是私有和那些數(shù)據(jù)是公眾的方式
解決方案是指出一個(gè)頁(yè)面的緩存應(yīng)該為"私有",使用cache_control視圖裝飾器來(lái)在Django中做這件事,例如:
Java代碼 復(fù)制代碼
  1. from django.views.decorators.cache import cache_control   
  2.   
  3. @cache_control(private=True)   
  4. def my_view(request):   
  5.     # ...  

這個(gè)裝飾器在幕后處理發(fā)送適當(dāng)?shù)腍TTP頭部
有一些其它控制緩存參數(shù)的方式,例如,HTTP允許程序做下面的事情:
1,定義一個(gè)頁(yè)面緩存的最大時(shí)間
2,指定一個(gè)緩存是否應(yīng)該一直檢查新的版本,只有在內(nèi)容沒(méi)有更改時(shí)發(fā)送緩存(一些緩存可能即使服務(wù)器頁(yè)面更改了也發(fā)送
緩存內(nèi)容--簡(jiǎn)單的因?yàn)榫彺婵截悰](méi)有過(guò)期)
在Django中使用cache_control視圖裝飾器來(lái)指定這些緩存參數(shù),這個(gè)例子中,cache_control告訴緩存對(duì)每次訪問(wèn)都重新驗(yàn)
證緩存并最多存儲(chǔ)緩存版本3600秒:
Java代碼 復(fù)制代碼
  1. from django.views.decorators.cache import cache_control   
  2. @cache_control(must_revalidate=True, max_age=3600)   
  3. def my_view(request):   
  4.     ...  

一些合法的Cache-Control HTTP指示在cache_control()中是合法的,這里是完整的列表:
1,public=True
2,private=True
3,no_cache=True
4,no_transform=True
5,must_revalidate=True
6,proxy_revalidate=True
7,max_age=num_seconds
8,s_maxage=num_seconds
參考規(guī)范http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9來(lái)得到Cache-Control HTTP指示
的解釋
(注意,緩存中間件已經(jīng)通過(guò)CACHE_MIDDLEWARE_SETTINGS設(shè)置來(lái)設(shè)置了緩存頭部的max-age,如果你在cache_control裝飾器
中使用自定義的max_age,裝飾器將優(yōu)先采用,而頭部的值會(huì)被正確的合并)

其它優(yōu)化
Django一些其它可以幫你優(yōu)化你的apps性能的中間件:
1,django.middleware.http.ConditionalGetMiddleware添加對(duì)現(xiàn)代瀏覽器的基于ETag和Last-Modified頭部的有條件的GET
應(yīng)答的支持
2,django.middleware.gzip.GZipMiddleware為所有現(xiàn)代瀏覽器壓縮應(yīng)答來(lái)節(jié)省帶寬和傳輸時(shí)間

MIDDLEWARE_CLASSES的順序
如果你使用CacheMiddleware,把它放在MIDDLEWARE_CLASSES設(shè)置的正確位置很重要,因?yàn)榫彺嬷虚g件需要知道改變緩存存儲(chǔ)
的頭部,把CacheMiddleware放在任何可能添加?xùn)|西到Vary頭部的中間件后面,包括:
1,SessionMiddleware,它添加Cookie
2,GZipMiddleware,它添加Accept-Encoding
安徽新華電腦學(xué)校專業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢
主站蜘蛛池模板: 石家庄团建公司|石家庄拓展训练|石家庄拓展培训|石家庄公司团建|石家庄拓展公司-石家庄启聚团建公司 | 烟囱防腐_维修_刷航标_美化_加固_刷色环 | 山东货架,山东仓库货架,临沂仓库货架,临沂仓储货架-山东兴博物流设备有限公司 | 运动控制器_数控系统_廊坊市九盈数控技术公司「官网」 | 洒水车厂家、消防车、污水处理车厂家-程力专用汽车股份有限公司 洒水车|冷藏车|LED广告车|油罐车|道路救援车|垃圾车|程力专用汽车股份有限公司销售九分公司 | 云南打砂机_昆明制砂机_云南砂石生产线_昆明洗砂机_昆明除尘设备_云南昆明滇重矿山机械设备有限公司 | 拉力机|拉力试验机|拉力测试机厂家-苏州天氏库力精密仪器有限公司 | 质量技术监督12365防伪追溯平台-www.12365china.net | 河北省金融租赁有限公司官网| 塑木地板-木塑地板厂家「云南昆明楚雄曲靖玉溪塑木地板」云南云冶中信塑木新型材料有限公司 | 长沙广告设计公司|长沙广告制作|湖南户外广告制作|商业美陈就找湖南盛翔文化传媒有限公司老品牌高品质 | 实验室装修设计-实验室工程建设-实验室实验台通风柜-瑞斯达实验室系统设备(苏州)有限公司 | 伸缩接头,限位伸缩接头,传力接头,可拆卸接头,橡胶接头,衬四氟橡胶接头,橡胶软连接,橡胶补偿器,防水套管- 巩义市隆盛管道设备有限公司 | 河南反渗透设备,河南纯净水设备,河南软化水设备,郑州EDI超纯水设备,郑州水处理设备厂家_河南江宇环保科技有限公司 | 全球环保研究网_生态环境绿色产业咨询部_生态文明建设行业智库 ? | 天津网站制作|网站建设|营销型网站建设|筑美网络---天津做网站公司 | 自动_链条式_电动推杆_电动开窗器厂家_山东鑫宏玺智能科技有限公司 | 加力管钳,液压动力钳,液压转盘-加力管钳,液压动力钳,液压转盘,山东临朐静远石油机械有限公司 | 洒水车_水车_洒水车价格_喷水车_绿化喷洒车_绿化洒水车- 程力专用汽车股份有限公司 | 学校直饮水机-反渗透纯水设备-家用净水器厂家-广州颖圣能源设备 学校洗碗机-郑州洗碗机厂家-商用洗碗机-郑州旭申环保科技有限公司 | 上海航空货运,上海空运,东方航空快递,机场物流,航空快运,上海东方航空托运公司 | 上海升降机_导轨式升降货梯_移动铝合金升降机_上海力盏电动液压平台厂家 | 宜宾三江人才网_三江人才网_宜宾三江人才网_三江人才直聘网是本地颇具规模的网上人才市场 | 河南康振机械有限公司 | 洒水车|冷藏车|LED广告车|油罐车|道路救援车|垃圾车|程力专用汽车股份有限公司销售九分公司 | 重庆木门_重庆木门十大品牌_重庆套装门_重庆烤漆门_重庆套装门十大品牌_重庆木门一线品牌_重庆川田木门 | 中国家居资讯网-家居建材-知名十大品牌-著名品牌资讯网 | 徐州护栏,铝艺栏杆,铝艺大门,铝艺栏杆门,别墅铝艺大门-徐州桂丰金属科技有限公司 | 威海华东数控股份有限公司 | 龙淼环保-旋流-喷淋塔,高温布袋,脉冲布袋-单机-滤筒除尘器,活性炭吸附箱,催化燃烧设备,除尘器配件-沧州龙淼环保设备制造有限公司 | 长沙物流公司|湖南货物运输公司|长沙第三方物流公司-国联物流 湖南第三方物流专家 | 球形钢支座,粘滞阻尼器,抗震球型钢支座,盆式橡胶支座,调谐质量阻尼器,屈曲约束支撑-衡水路泽科技 | 激光清洗机_激光除锈机_激光焊接机 - 上海锡昊激光科技有限公司 激光切管机_等离子切管机_相贯线切管机厂家|服务为先-山东美峰智能设备有限公司 | 上海喷涂厂|上海喷漆厂|粉末喷涂|平湖喷涂厂|平湖喷漆厂-平湖华梦金属科技有限公司 | 深山工作室提供网络投票系统|微信公众号投票|微信公众号小程序|抖音小程序|百度小程序|微信公众号开发|企业网站建设 | 舞台阻燃幕布_舞台幕布_舞台吊杆_舞台机械_TYWT-泰州通用舞台设备有限公司 | 山东万利精密机械制造有限公司-高速金属圆锯机,数控高速圆锯机,高速圆锯机生产厂家 | 上海浩斌信息科技有限公司RFID读写器,IC卡读卡器,手持机,数据采集终端,电力仓库管理软件开发,固定资产软件,纱管标签,试剂管理,RFID试剂柜,档案管理,档案柜,智能货架 | 久久黄色一级视频_视频一区精品自拍_理论片免费ā片在线观看_亚洲色视频在线播放网站_香港经典a毛片免费观看_亚州三级久久电影 | 暖气片_铜铝复合暖气片_钢制散热器厂家-德克菲勒暖气片 | 九江赛璐珞实业有限公司-赛璐珞板,赛璐璐板材,PVC装饰膜,PVC片材,醋酸纤维胶板_多彩装饰材料生产厂家 |