HTTP典型應(yīng)用于能通過采用緩存技術(shù)而提高性能的分布式信息系統(tǒng)。HTTP/1.1協(xié)議包括的許多使緩存盡可能的工作的元素。因為這些元素與協(xié)議的其他方面有著千絲萬縷的聯(lián)系,而且他們相互作用、影響,因此有必要單獨的來介紹基本的緩存設(shè)計。
如果緩存不能改善性能,他將一無用處。HTTP/1.1中緩存的目的是為了在很多情況下減少發(fā)送請求,同時在許多情況下可以不需要發(fā)送完整響應(yīng)。前者減少了網(wǎng)絡(luò)回路(譯注:一個請求會返回一個響應(yīng),請求響應(yīng)這個過程就是一個回路)的數(shù)量;我們利用一個“過期(expiration)”機制來為此目的(見13.2節(jié))。后者減少了網(wǎng)絡(luò)應(yīng)用的帶寬;我們用“驗證(validation)”機制來為此目的。
對行為,可行性,和關(guān)閉的操作的要求放松了語義透明性的目的。HTTP/1.1協(xié)議允許服務(wù)器,緩存,和客戶端能顯示地降低透明性當在必要的時候。然而,因為不透明的操作能混淆非專業(yè)的用戶,同時可能和某個服務(wù)器應(yīng)用程序不兼容(例如訂購商品),因此此協(xié)議透明性在下面情況下才能被放松要求:
-- 只有在一個顯示的協(xié)議層的請求時,透明性才能被客戶端或源服務(wù)器放松
-- 當出現(xiàn)一個對終端用戶的顯示的警告時,透明性才能被緩存或被客戶端放松
因此,HTTP/1.1協(xié)議提供這些重要的元素:
1.提供完整語義透明的協(xié)議特征,當這些特征被通信的所有方需要時
2. 允許源服務(wù)器或用戶代理顯示的請求和控制不透明操作的協(xié)議特征
3. 允許緩存給這樣的響應(yīng)綁定警告信息的協(xié)議特征,這些響應(yīng)不能保留請求的語義透明的近似
一個基本的原則是客戶端必須能夠發(fā)現(xiàn)語義透明性的潛在的放松。
注意:服務(wù)器,緩存,或者客戶端的實現(xiàn)者可能會面對設(shè)計上的判斷,而這些判斷沒有顯示地在此規(guī)范里討論。如果一個判斷可能會影響語義透明性,那么實現(xiàn)者應(yīng)該能維持語義透明性,除非一個仔細的完整的分析能說明打破透明性的好處。
13.1.1緩存正確性(Cache Correctness)
一個正確的緩存必須能用最新的響應(yīng)來響應(yīng)請求,此響應(yīng)當在下面的條件滿足時才適合此請求(見13.2.5,13.2.6,和13.12)?
此緩存響應(yīng)已被檢測與假設(shè)通過源服務(wù)器重驗證后源服務(wù)器返回的響應(yīng)相等價。
此緩存響應(yīng)是足夠保鮮(fresh)的(見13.2節(jié))。缺省的情況下,這意味著此響應(yīng)必須滿足客戶端,源服務(wù)器,和緩存的最嚴格的保鮮要求(見14.9節(jié));如果源服務(wù)器指定了保鮮壽命,這說明它是源服務(wù)器自己的保鮮要求。
由于客戶端和源服務(wù)器的最嚴格的保鮮要求,如果一個緩存的響應(yīng)不是足夠保鮮的,那么在仔細考慮的情況下,緩存可能仍然返回此緩存的響應(yīng)通過合適的Warning頭域(見13.1.5和14.46節(jié)),除非此響應(yīng)被阻止(例如:通過”no-store” cache-directive ,或者通過一個”no-cache”cache-request-directive;見14.9節(jié))。
此緩存響應(yīng)是一個304(沒有被改變),305(代理重定向),或 錯誤(4xx或者5xx)響應(yīng)消息。
如果緩存不能同源服務(wù)器通信,那么一個正確的緩存應(yīng)該用它緩存的響應(yīng)去響應(yīng)請求,如果此緩存的響應(yīng)能正確的服務(wù)于請求;如果不能服務(wù)器于此請求,那么緩存必須能返回一個錯誤或警告指示存在通信失敗。
如果緩存從服務(wù)器端接收到一個響應(yīng)(或者是一個完整的響應(yīng),或者一個304(沒有被改變)的響應(yīng)),此響應(yīng)應(yīng)該是正常情況下要發(fā)送到請求的客戶端的,并且此響應(yīng)并不是新鮮的,那么此緩存應(yīng)該把此響應(yīng)轉(zhuǎn)發(fā)給請求客戶端不需要添加一個新的Warning頭域(但是沒有移去已經(jīng)存在的Warning頭域)。緩存并不是簡單的因為傳輸中響應(yīng)變得陳舊而嘗試去重驗證響應(yīng);這可能會導致一個無限的循環(huán)。用戶代理接收一個陳舊的沒有Warning頭域的響應(yīng)應(yīng)該提示用戶一個警告信息。
13.1.2警告信息(Warnings)
無論何時,緩存返回一個響應(yīng),此響應(yīng)既不是第一手的(first-hand)也不是足夠保鮮(在13.1.1節(jié)的條件2),那么緩存必須利用一個Warning常用頭域來警告產(chǎn)生的效果。Warning頭域和當前定義的警告在14.46節(jié)里描述。這些警告允許客戶端去采取合適的動作。
警告可能被用于其他的目的,和緩存相關(guān)的目的和其他的目的。警告和錯誤狀態(tài)碼的區(qū)別在于是否是真正的失敗。
警告被賦予三位數(shù)字warn-codes。第一個數(shù)字指明:警告是否必須或不必須從緩存項里刪除,在一個成功的重驗證之后。
1xx 警告描述了響應(yīng)的保鮮或重驗證狀態(tài)信息,并且這些信息應(yīng)該在一個成功的重驗證之后刪除。1xx警告碼可能是由緩存產(chǎn)生的,當緩存驗證一個緩存項時。此警告碼不能被客戶端產(chǎn)生。
2xx 警告描述了實體主體或?qū)嶓w頭域的某些方面的信息,這些信息不能被重驗證修改,并且這些信息不能在一個成功重驗證之后被刪除。
見14.46節(jié)關(guān)于警告碼的定義。
HTTP/1.0緩存將緩存所有響應(yīng)中的警告,并且不會刪除第一類警告。穿過HTTP/1.0緩存響應(yīng)中的警告會攜帶一個額外的warning-date域,這是為了防止將來的HTTP/1.1接收端信任一個錯誤的緩存警告。
警告同樣攜帶一個警告文本。此文本可能是任何合適的自然語義(可能基于客戶端請求的Accept頭域),同時包含一個可選擇的關(guān)于何種字符集被使用的聲明。
多個警告可能會綁定一個響應(yīng)(或者被源服務(wù)器或者被一個緩存發(fā)送的),這包括多個警告可以共用一個警告碼。例如,服務(wù)器可能會以英語和法語提供相同的警告。
當多個警告綁定一個響應(yīng)時,有時候不可能把所有的警告都展示給客戶。HTTP版本不能指定一個嚴格的優(yōu)先值去決定警告的優(yōu)先和順序顯示,但是可以探索一些方法。
13.1.3緩存控制機制 (Cache-control Mechanism)
HTTP/1.1基本的緩存機制(服務(wù)器指定過期時間和驗證器)對緩存是隱含的指令。某些情況下,服務(wù)器或客戶端可能需要給HTTP緩存提供顯示的指令。我們利用Cache-Control頭域為此目的。
Cache-Control頭域允許客戶端或服務(wù)器在請求或響應(yīng)里傳輸多個指令。這些指令常常覆蓋缺省的緩存算法。作為一個常用規(guī)則,如果頭域值中存在一個明顯的沖突,那么最具嚴格解釋的頭域值會被應(yīng)用(也就是說,能保留語義透明性的值)。然而,一些情況下,cache-control指令被顯示地指定用來削弱語義透明性的相似性(例如,”max-stale” 或者 “public”)。
Cache-control指令在14.9節(jié)被描述。
13.1.4顯示的用戶代理警告(Explicit User Agent Warnings)
很多用戶代理允許用戶覆蓋基本緩存機制。例如,用戶代理可能允許用戶指定緩存實體(即使實體明顯是陳舊的)從來不要被驗證?;蛘?,用戶代理可能習慣于給任何請求加上“Cache-Control:max-stale=3600”。用戶代理不能缺省的執(zhí)行不透明行為,或者不能缺省的執(zhí)行導致非正常的無效率的緩存行為,但是可能被顯示地設(shè)置去這樣做通過一個顯示的用戶動作。
如果用戶已經(jīng)覆蓋基本的緩存機制,那么用戶代理應(yīng)該給用戶指示何時顯示不能滿足服務(wù)器透明要求的信息(特別地,如果顯示的實體被認為是陳舊的)。因為此協(xié)議通常允許用戶代理去判定響應(yīng)是否是陳舊或不是陳舊的,所以此指示只需要當實際發(fā)生時顯示。此指示不必是對話框;它應(yīng)該是一個圖標(例如,一個正在腐爛的魚)或者一些其他的指示器。
如果用戶以一種方式已經(jīng)覆蓋了緩存機制,這種方式可能不正常地減少緩存效率,那么用戶代理應(yīng)該繼續(xù)指示用戶的狀態(tài)(例如,通過一個圖片顯示)以便用戶不能不注意地消費過度的資源或者忍受過度的延遲。
13.1.5規(guī)則和警告的例外情況
在某些情況下,緩存的操作者應(yīng)該設(shè)置緩存返回陳舊的響應(yīng),即使此響應(yīng)沒有被客戶端請求。這個判定本來不應(yīng)該輕易決定,但是由于某些原因可能會這樣做,特別是當緩存和源服務(wù)器連接不好時。無能何時當緩存會返回一個陳舊的響應(yīng)時,緩存必須給此響應(yīng)做個標記(利用Warning頭域),因為這樣能使客戶端提示用戶響應(yīng)是陳舊的。
用戶代理照樣能采取步驟去獲得第一手的或保鮮的響應(yīng)。由于這個原因,如果客戶端顯示地請求第一手的或保鮮的響應(yīng),緩存就不能返回一個陳舊的響應(yīng),除非由于技術(shù)或策略方面的原因。
13.1.6由客戶控制的行為(Client-controlled Behavior)
當源服務(wù)器是過期信息得主要來源時,有時候客戶端可能需要控制緩存去判定是否返回一個緩存響應(yīng)而不需要緩存通過服務(wù)器驗證它??蛻舳送ㄟ^利用一些Cache-Control頭域來達到此目的。
客戶端的請求可能會指定自己愿意接受一個沒有驗證的響應(yīng)的最大的年齡(age);指定0值會強迫緩存重驗證所有的響應(yīng)。客戶端照樣會指定在響應(yīng)過期前的最小保持時間。這些選項增加了對緩存行為的限制,同時這樣做并不能進一步地放松緩存語義透明的近似。
客戶端可能照樣會指定它會接受陳舊響應(yīng)直到陳舊數(shù)達到最大數(shù)量。這放松了對緩存的限制,同時這可能違反了源服務(wù)器指定對語義透明性的限制,但是這可能支持無連接的操作或者高獲得性當連接不好時。
13.2 過期模型 (Expiration Model)
13.2.1 服務(wù)器指定模型(Server-Specified Expiratiion)?
HTTP緩存會工作的很好,這是因為緩存能完全地避免客戶端對源服務(wù)器的請求。避免對源服務(wù)器請求的主要機制是服務(wù)器將來會提供一個顯示過期時間(explicit expiration time),此顯示過期時間用來指示響應(yīng)可能會滿足后續(xù)的請求。也就是說,客戶端請求響應(yīng)時,緩存能返回一個保鮮(fresh)的響應(yīng)而不需要從源服務(wù)器那里獲得。
我們希望服務(wù)器給響應(yīng)設(shè)置顯示過期時間(explicit expiration time),服務(wù)器相信在過期時間之前實體不會改變。這能保持語義透明性(譯注:語義透明性情況1.3節(jié)里關(guān)于“語義透明”的解釋),只要服務(wù)器對過期時間仔細選擇。
過期機制只能應(yīng)用于能從緩存獲得的響應(yīng),不能應(yīng)用于客戶端請求的第一手(first-hand,見1.3節(jié)術(shù)語)的響應(yīng)。
如果源服務(wù)器希望強制一個語義透明緩存去驗證每個請求,它會使顯示過期時間(explicit expiration time)設(shè)為過去。這就是說響應(yīng)總是陳舊的,所以此緩存應(yīng)該驗證此響應(yīng)當緩存利用此響應(yīng)去服務(wù)于后續(xù)的請求時。見14.9.4節(jié),有更多強迫重驗證的方法
如果源服務(wù)器希望強迫任何HTTP/1.1緩存(不管此緩存是怎樣設(shè)置的)去驗證每一個請求,源服務(wù)器應(yīng)該在Cache-Control頭域里指定“must-revalidate”緩存控制指令(見14.9節(jié))。
源服務(wù)器利用Expires頭域或在Cache-Control頭域里通過max-age緩存控制指令,來指定顯示過期時間(explicit expiration time)。
過期時間不能被用于強制客戶代理去重新刷新它的顯示或重載資源;過期的語義只能應(yīng)用于緩存機制,并且這個機制值只需要檢測資源的過期狀態(tài)當請求那個資源的一個新請求發(fā)生時。見13.13節(jié),關(guān)于緩存和歷史機制的區(qū)別。
13.2.2 啟發(fā)式過期
因為源服務(wù)器不能總是提供一個顯示過期時間(explicit expiration time),HTTP緩存通常會設(shè)置一個啟發(fā)式過期時間(heuristic expiration time),它采用一種算法,此算法利用其它的值(例如Last-Modified時間)去估計一個似乎合理的過期時間。HTTP/1.1規(guī)范沒有提供特定的算法,但是的確是加強了對這些算法結(jié)果的最壞情況的限制。因為啟發(fā)式過期時間可能會對語義透明性妥協(xié),他們本應(yīng)該被謹慎地使用,并且我們鼓勵源服務(wù)器盡可能提供顯示過期時間。
13.2.3 年齡(Age)計算
為了了解緩存項(譯注:緩存項是用來響應(yīng)請求的,它包含緩存的響應(yīng)實體)是否是保鮮的(fresh),緩存需要知道其年齡是否已超過保鮮壽命(freshness lifetime)。我們在13.2.4節(jié)中討論如何計算保鮮壽命,本節(jié)討論如何計算響應(yīng)或緩存項的年齡。
在此討論中我們用“now”來表示主機進行計算時時鐘的“當前值”。使用HTTP協(xié)議的主機,特別是運行于源服務(wù)器和緩存的主機,應(yīng)該使用NTP[28] 或其他類似協(xié)議來將其時鐘同步到一個全球性的精確時間標準上。
HTTP1.1協(xié)議要求源服務(wù)器盡可能在發(fā)送每條響應(yīng)時都附加一個Date頭域,要盡可能在每個響應(yīng)里給出響應(yīng)產(chǎn)生的時間(見14.18節(jié))。我們利用術(shù)語“date_value”去表示Date頭域的值,這是一種適合于運算操作的表示方法。
當從緩存里獲取響應(yīng)消息時,HTTP/1.1利用Age響應(yīng)頭域來傳送響應(yīng)消息的估計年齡。Age響應(yīng)頭域值是緩存對響應(yīng)從產(chǎn)生或被重驗證開始到現(xiàn)在的時間估計值。
實際上,年齡的值是響應(yīng)從源服務(wù)器途徑每一個緩存的逗留時間的總和,再加上響應(yīng)在網(wǎng)絡(luò)路徑上傳輸?shù)臅r間。
我們用“age_value”來表示Age頭域的值,這是一種適于算術(shù)操作的表示方法。
一個響應(yīng)的年齡(age)可以通過兩種完全不同的途徑來計算::
如果本地時鐘與源服務(wù)器時鐘同步的相當好,則用 now - date_value ,若結(jié)果為負,則取零。
如果途徑響應(yīng)路徑(response path)的所有緩存均遵循HTTP1.1協(xié)議,則用age_value。
如果我們有兩種獨立的方法計算響應(yīng)的年齡(譯注:注意這里是響應(yīng)的年齡),我們可以合并二者如下:
corrected_received_age = max(now – date_value,age_value)?
并且只要我們或者有同步的時鐘或者響應(yīng)途徑的所有緩存遵循HTTP/1.1,我們就能得到一個可信賴的結(jié)果。
由于網(wǎng)絡(luò)附加延時,一些重要時隙會在服務(wù)器產(chǎn)生響應(yīng)與下一個緩存或客戶端接收之間流逝。如果不經(jīng)修訂,這一延遲會帶來不正常的低年齡。
由于導致產(chǎn)生年齡值的請求(譯注:就是存在Age頭域的請求)是早于年齡值的產(chǎn)生,我們能校正網(wǎng)絡(luò)附加延遲通過記錄請求產(chǎn)生的時間。然后,當一個年齡值被接收后,它必須被解釋成相對于請求產(chǎn)生的時間,而不是相對響應(yīng)接收的時間。不管有多少延遲,此算法會導致穩(wěn)定的結(jié)果。所以,我們計算:?
corrected_initial_age = corrected_received_age + (now - request_time)
這里“request_time”是請求的發(fā)送時間。
緩存收到響應(yīng)時,它計算響應(yīng)年齡的算法如下:
/*?
* age_value?
* is the value of Age: header received by the cache with this response.?
* date_value?
* is the value of the origin server's Date: header?
* request_time?
* is the (local) time when the cache made the request?
* that resulted in this cached response?
* response_time?
* is the (local) time when the cache received the response?
* now?
* is the current (local) time?
*/?
apparent_age = max(0, response_time - date_value); //緩存收到響應(yīng)時響應(yīng)的年齡
corrected_received_age = max(apparent_age, age_value);
response_delay = response_time - request_time;?
corrected_initial_age = corrected_received_age + response_delay;?
resident_time = now - response_time; //即收到響應(yīng)到現(xiàn)在的時間間隔
current_age = corrected_initial_age + resident_time;?
緩存項(cache entry)的current_age是緩存項從被源服務(wù)器最后驗證開始到現(xiàn)在的時間間隔(以秒記)加上corrected_initial_age。當從緩存項里產(chǎn)生一條響應(yīng)時,緩存必須在響應(yīng)里包含一個Age頭域,它的值應(yīng)該等于緩存項的current_age值。
Age頭域出現(xiàn)在響應(yīng)里說明響應(yīng)不是第一手的(first-hand)(譯注:第一手的說明,響應(yīng)是直接來自于源服務(wù)器到達接收端的,而不是來自于緩存里保存的副本)。然而相反的情況并不成立,因為響應(yīng)里缺少Age頭域并不能說明響應(yīng)是第一手的(fisrt-hand),除非所有請求路徑上的緩存都遵循HTTP/1.1協(xié)議(也就是說,以前HTTP版本緩存沒有定義Age頭域)。?
13.2.4 過期計算(Expiration Calculations)
為了確定一條響應(yīng)是保鮮的(fresh)還是陳舊的(stale),我們需要將其保鮮壽命(freshness lifetime)和年齡(age)進行比較。年齡的計算見13.2.3節(jié),本節(jié)講解怎樣計算保鮮壽命,以及判定一個響應(yīng)是否已經(jīng)過期。在下面的討論中,數(shù)值可以用任何適于算術(shù)操作的形式表示。?
我們用術(shù)語“expires_value”來表明Expires頭域的值。我們用術(shù)語“max_age_value”來表示Cache-Control頭域里“max-age”控制指令的值(見14.9.3節(jié))。
max-age指令優(yōu)于Expires頭域執(zhí)行,所以如果max-age出現(xiàn)在響應(yīng)里,那么定義如下:
freshness_lifetime = max_age_value?
否則,若Expires頭域出現(xiàn)在響應(yīng)里,定義如下:
freshness_lifetime = expires_value - date_value?
注意上述運算不受時鐘誤差影響,因為所有信息均來自源服務(wù)器。?
如果Expires, Cache-Control:max-age, 或 Cache-Control:s-maxage (見 14.9.3) 均未在響應(yīng)中出現(xiàn),且響應(yīng)沒有包含對緩存的其他控制,那么緩存可以用啟發(fā)式算法計算保鮮壽命(freshness lifetime)。緩存器必須對年齡大于24小時的響應(yīng)附加113警告,如果此響應(yīng)不帶這種警告。
而且,如果響應(yīng)有最后修改時間,啟發(fā)式過期值應(yīng)不大于從那個時間開始間隔的某個分數(shù)。典型設(shè)置為間隔的10% 。
計算響應(yīng)是否過期非常簡單:
response_is_fresh = (freshness_lifetime > current_age)
13.2.5澄清過期值(Disambiguation Expiration Values)
由于過期值很容易被設(shè)置,有可能兩個緩存會包含同一資源的不同保鮮值。
如果客戶端執(zhí)行請求接收到一個非第一手的響應(yīng),此響應(yīng)在此客戶端擁有的緩存里仍然是保鮮的,并且緩存里的緩存項里的Date頭域的值比此新響應(yīng)的Date頭域值要新,那么客戶端應(yīng)該忽略此響應(yīng)。如果這樣,它可能會重新以“Cache-Control:max-age=0”指令(見14.9節(jié))請求去強制任何中間緩存通過源服務(wù)器對其進行檢查。
如果緩存對有不同驗證器(validator)的同一個表現(xiàn)形式(representation)有兩個保鮮響應(yīng),那么緩存必須利用Date頭域值最近的響應(yīng)。這種情況可能發(fā)生由于緩存會從其他緩存得到響應(yīng),或者由于客戶端請求對一個保鮮緩存項的重載或重驗證(revalidation)。
13.2.6澄清多個響應(yīng)(Disambiguating Multiple Response)
因為客戶端可能收到經(jīng)多個路徑而來的響應(yīng),所以有些響應(yīng)會經(jīng)過一些緩存,而其他的響應(yīng)會經(jīng)過其他的緩存,客戶端收到響應(yīng)的順序可能與源服務(wù)器發(fā)響應(yīng)的順序不同。我們希望客戶端利用最新的響應(yīng),即使舊響應(yīng)仍然是保鮮的。
實體標簽(entity tag)和過期值都不能影響響應(yīng)的順序,因為可能會出現(xiàn)晚一點的響應(yīng)可能會故意攜帶過早的過期時間。日期值的精度被規(guī)定只有一秒。?
當客戶端試著重新驗證一個緩存項的時候(譯注:這里的客戶端應(yīng)該包含一個本地緩存),而且接收到的響應(yīng)的Date頭域晚于已存在的緩存項,那么客戶端應(yīng)該重新進行無條件請求,并且包含
Cache-Control: max-age=0?
去強制任何中間緩存通過源服務(wù)器來驗證(validate)這些中間緩存的副本,或者
Cache-Control: no-cache?
去強制任何中間緩存去從源服務(wù)器獲得一個新的副本。
13.3 驗證模型(Validation Model)
當緩存有一個舊緩存項并且緩存想利用此緩存項來作為客戶端請求的響應(yīng)時,緩存必須首先通過源服務(wù)器(或者可能通過一個有保鮮響應(yīng)的中間緩存)對其進行檢驗看看此緩存項是否可用。我們稱做“驗證(validating)”此緩存項。因為我們不想對完整響應(yīng)的傳輸付出太大代價,而且如果緩存項無效時也不會產(chǎn)生額外的回路(譯注:回路的意思,如:從請求到響應(yīng)就一條回路),HTTP1.1協(xié)議支持使用條件方法。.?
協(xié)議支持條件方法的關(guān)鍵特征是圍繞“緩存驗證器(cache validator)”展開的。當源服務(wù)器產(chǎn)成一個完整響應(yīng)時,它同時會附加一些驗證器給響應(yīng),這些驗證器和緩存項一起保存。當客戶端(用戶代理或緩存服務(wù)器)對對應(yīng)有緩存項的資源執(zhí)行條件請求時,客戶端包含一個相關(guān)的驗證器(validator)在請求里。
<br style="color:rgb(24,95,24);font-family:Georgia;font