2011-06-27 45 views
12

我想弄清楚最好的HTTP標頭髮送四個用例。我希望拿出不依賴於用戶代理/協議版本嗅探的頭文件,但我會接受,如果沒有其他適合。所有URL都通過完全自定義處理程序獲取,因此我可以根據需要選擇所有標題,這全部是關於中間代理和用戶代理。如果可能的話,這應該與HTTP/1.0和HTTP/1.1客戶端兼容。如果存在多種解決方案,通過電線發送時最好的解決方案將是最短的解決方案。HTTP頭:控制緩存和歷史機制

靜態公共內容

所有「靜態公共含量」的東西,HTTP的真正意義:如果URL是一樣的,內容是一樣的。我可以輕鬆地做到這一點:例如,我將用戶配置文件圖標放入http://domain.com/profiles/xyz/icon/1234abcd,其中「1234abcd」是圖標文件內容的SHA-1。如果我將來更改爲圖標,我將創建一個新的URL並修改所有應該使用新圖標的現有推薦人。什麼是最好的頭文件來聲明這可能會永久緩存並可能被共享?我目前正在思考一些問題:

Date: <current time> 
Expires: <current time + one year> 

這是否足以允許用戶代理和代理進行緩存?我需要Last-Modified還是Pragma

靜態非公開內容

所有「靜態非公開內容」的東西,是靜態的,但可能無法提供給大家。實際上,這些內容僅對選定的登錄用戶可用(會話保持會話cookie保持會話UUID)。如果URL相同,則內容相同。但是,迴應並不公開。用例可以是社交網絡服務中選定好友共享的圖片。我目前在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=<huge number>, s-maxage=0 

這足以讓用戶代理緩存和禁用代理嗎?我需要Pragma嗎?

揮發公開內容

所有「揮發性公開內容」的東西,易揮發,提供給大家。類似於http://slashdot.org/的首頁,當未登錄時。意圖是允許快速更新不變URL中的內容。 請注意,我不想破壞用戶代理歷史機制(即,從易失性頁面中單擊某些內容,然後點擊後退按鈕不應導致從服務器獲取易失性頁面 - 但是,請單擊一個鏈接去首頁應該從服務器獲取資源)。我目前正在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: public, max-age=0, s-maxage=0 

這足以防止緩存但允許歷史機制(後退按鈕)?我知道,如果我發送Cache-Control: no-store, must-revalidate我可以強制重新加載,但這不是我想要的,因爲這也會打破後退按鈕。我需要Last-Modified還是Pragma

儘管這是公開的,但允許中間代理緩存此內容可能沒有意義,因爲它是不穩定的。

揮發性非公開內容

所有「揮發性非公開內容」的東西,易揮發,不提供給大家(私人)。類似於登錄時的http://slashdot.org/的頭版。意圖是允許快速更新不變URL中的內容。 請注意,我不想破壞用戶代理歷史機制(即,從易失性頁面中單擊某些內容,然後點擊後退按鈕不應導致從服務器獲取易失性頁面 - 但是,請單擊一個鏈接去首頁應該從服務器獲取資源)。我目前在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=0, s-maxage=0 

這足以防止緩存但允許歷史機制(後退按鈕)?我需要Pragma嗎?


的事情,還需要我的建議的首部測試:

  • 驗證私人內容將無法通過HTTP/1.0代理被泄露。
  • 驗證緩存在代理中是否正常工作。
  • 確認緩存在用戶代理中正常工作。
  • 驗證用戶代理歷史記錄機制在用戶代理(所有情況下)中工作。
  • 驗證在鏈接到易失性頁面後,從服務器獲取新鮮內容。
  • 使用HTTPS而非HTTP驗證所有結果。
+0

我知道以前的類似問題在http://stackoverflow.com/questions/2970938/ideal-http-cache-control-headers-for-different-types-of-resources - 但是,這是缺少三個重要的難題:後退按鈕行爲,用戶代理兼容性和HTTP/1.0代理支持。 –

+0

另一個經常引用的來源http://www.mnot.net/cache_docs/也受到不處理現實世界的用戶代理行爲與後退按鈕和HTTP/1.0代理支持。 –

+0

這裏有一篇關於緩存控制的文章:http://palisade.plynt.com/issues/2008Jul/cache-control-attributes/ - 也缺少真實世界的後退按鈕行爲,用戶代理兼容性和HTTP/1.0代理支持。 –

回答

10

我會回答,會發生什麼我自己的問題:

靜態公共內容

Date: <current time> 
Expires: <current time + one year> 

理由:這是與HTTP/1.0代理和RFC 2616第14節兼容:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21 Last-Modified標頭對於正確的緩存不是必需的(因爲符合標準的用戶代理遵循Expires標題),但可能包含在最終用戶消費中。如果用戶點擊重新加載/刷新按鈕,包括Last-Modified標題也可能會減少服務器數據傳輸。如果添加了Last-Modified標題,它應該反映真實的數據而不是發明的東西。如果您想減少服務器數據傳輸(如果用戶點擊重新加載/刷新按鈕)並且不能包含真實的標頭,則可以添加ETag標頭以允許有條件的GET(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26)。如果您已經包含Last-Modified也加入ETag只是浪費。請注意,Last-Modified顯然更好,因爲它也支持HTTP/1.0客戶端和代理。對於動態頁面,ETag的合適值是頁面/資源內容的SHA-1。請注意,使用Last-ModifiedETag將無助於服務器負載,只能使用服務器傳出互聯網管道/數據傳輸速率。

靜態非公開內容

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=31536000, s-maxage=0 
Vary: Cookie 

理由:DateExpires頭對於HTTP/1.0的兼容性和因爲有指定的響應是私人沒有明智的方法,這些標題傳達的響應可能不會被緩存。 Cache-Control標頭表明此響應可能會被私有緩存緩存,但共享緩存可能不緩存該響應。 s-maxage=0被添加,因爲private可能不支持所有代理支持Cache-Controlhttp://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3 - 我不知道哪個代理被破壞)。 max-age設置爲60*60*24*365(1年)的值,因爲HTTP/1.1規範沒有定義這個參數的任何上限,我想這是依賴於實現的。 Expires頭將在未來限制爲一年,所以在這裏使用相同的邏輯應該沒問題。 Vary: Cookie標頭是必需的,因爲用於檢查訪問者是否被允許查看內容的會話在cookie中傳輸;因爲返回的響應取決於cookie值,所以如果cookie頭被更改,則緩存可能不會使用緩存響應。

我可能會親自打破最後一部分。通過不包含Vary: Cookie標題,我可以提高緩存的質量。例如:我有一個檔案圖像http://domain.com/icon/12,這個檔案圖片只會返回給選定的認證用戶。我有一個訪問者X,會話ID爲5f2,我允許該用戶的圖像。訪問者X註銷,然後再次登錄。現在X的會話ID爲2e8存儲在他的會話cookie中。如果我有Vary: cookie,則用戶代理X不能使用緩存圖像,並且強制將其重新加載到其緩存中。由於內容因Cookie而異,因此無法使用具有上次修改時間的條件GET。我還沒有測試在這種情況下使用ETag是否有幫助,因爲在這種情況下,服務器響應將是相同的(匹配從響應內容計算的SHA-1 ETag)。需要警告的是,Internet Explorer(至少是版本9)總是強制條件GET包含Vary: Cookie(來源:http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx)的資源。這是因爲MSIE的內部緩存實現不記得它第一次發送哪個Cookie,因此無法知道當前Cookie是否是同一個Cookie。

但是,下面是一個由於丟失Vary: Cookie標題而導致的問題示例,以說明爲什麼確實需要技術上正確的行爲。看看上面的例子,想象一下,在X退出之後,訪問者Y用相同的用戶代理登錄(用戶代理可能已經在X和Y之間重新啓動,這沒關係)。如果Y查看包含指向http://domain.com/icon/12的鏈接的頁面,則Y會在頁面內嵌入圖標,即使Y以前沒有使用過相同的用戶代理,Y也無法看到該圖標。在我的情況下,我不認爲這是一個足夠大的問題,因爲Y可以通過檢查用戶代理緩存手動訪問圖標,無論可能添加Vary: Cookie。但是,這個問題可能會阻止Y注意到他不會在技術上訪問此內容(這可能很重要,例如,如果Y是共同創作內容的話)。如果內容被認爲是敏感的,服務器必須發送no-store,而不管這個Cache-Control指令引起的問題。

此處,添加Last-Modified標題將有助於用戶點擊重新加載/刷新按鈕(請參閱上面的討論)。

揮發公開內容

Date: <current time> 
Expires: <current time> 
Cache-Control: public, max-age=0, s-maxage=0 
Last-Modified: <real-last-modification-time> 

理由:告訴HTTP/1.0客戶端和代理這種反應,應立即認爲是過時的。包含Last-Modified時間以允許在資源再次訪問時跳過內容數據傳輸,並且客戶端支持條件GET。如果不能使用Last-Modified,則可以使用ETag作爲替換(參見上面的討論)。使用Last-Modified來允許HTTP/1.0兼容客戶端的條件GET至關重要。

如果內容可能會稍有延遲,則應適當調整Expiresmax-ages-maxage [原文如此]。例如,如symcbean的答案所暗示的,爲這些人添加5秒鐘可能對高度流行的網站有很大幫助。請注意,與條件GET不同,增加到期時間將減少服務器負載,而不僅僅是減少服務器傳出數據通信量(因爲服務器總共會看到較少的請求)。

揮發性非公開內容

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=0, s-maxage=0 
Last-Modified: <real-last-modification-time> 
Vary: Cookie 

理由:告訴HTTP/1.0客戶端和代理這種反應,應立即認爲是過時的。包含Last-Modified時間以允許在資源再次訪問時跳過內容數據傳輸,並且客戶端支持條件GET。如果不能使用Last-Modified,則可以使用ETag作爲替換(參見上面的討論)。使用Last-Modified來允許HTTP/1.0兼容客戶端的條件GET至關重要。還請注意,Cache-Control不得包含no-cache,must-revalidateno-store,因爲使用這些指令中的任何一個都會打破至少一個用戶代理中的後退按鈕。但是,如果服務器傳輸的內容包含不應存儲在永久存儲器中的敏感內容,則必須使用no-store標誌,而不管中斷後退按鈕。 警告:請注意,如果操作系統啓用了交換並且交換未加密,則使用no-store無法防止敏感內容在硬盤上未經加密而結束! 另請注意,除非連接已加密(HTTPS/SSL),否則使用no-store意義不大。

2

晴OK,不過,你需要牢記的是HTTP 1.0的代理可以緩存內容提供/最多爲

Cache-Control: private 

因此隨着到期,你應該設定一個明確的日期修改的標頭,以及承擔頭。

對於您的'靜態非公開內容',您應該添加'Varies:Cookie'標頭。

對於您的「易變的公共內容」:它變化的速度有多快?設置+5秒的TTL可能會減輕服務器的工作量。

對於'非易失性非公開內容',您應該添加no-cache,並且必須對Cache控制標題進行重新驗證。

從服務器發出的Pragma頭應該不會影響客戶端或代理服務器。

做測試出你的時候緩存過期(IME,你可以結束了不止一個沒有填充緩存訪問由於所有條件要求更慢的系統/ 304響應)

+0

我知道'Cache-Control:private'不能被HTTP/1.0代理理解。這就是我把'Date'和'Expires'放到當前時間的原因。如果我理解正確,這應該立即從HTTP/1.0代理中過期。爲什麼我需要顯式的'Date-Modified'頭文件?某些用戶代理是否需要它? –

+0

我認爲在'非易失性非公開內容'中添加'no-cache,must-revalidate'將會打破至少Firefox和Internet Explorer的後退按鈕。如果可能的話,我的意圖是保持按鈕顯示實際的歷史記錄(而不是透明的服務器狀態視圖);有關詳細信息,請參閱http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13。 –

+0

我認爲標題語法是'Vary:Cookie'。我曾考慮過這個問題,但是因爲用戶代理(瀏覽器)也承認這個頭部會破壞用戶代理緩存。例如:我在'http:// domain.com/icon/12'上有一個配置文件映像,它只爲選定的已認證用戶返回。我有一個會話ID爲'5f2'的訪問者X,我允許圖像給那個用戶。訪客X註銷,然後再次登錄。現在X的會話ID爲'2e8',存儲在會話cookie中。如果我有'Vary:cookie',則X的用戶代理不能使用緩存的圖像。從技術上講,'Vary:cookie'應該是正確的。 –