日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

HTTP中的缓存

發布時間:2023/11/27 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HTTP中的缓存 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
HTTP典型應用于能通過采用緩存技術而提高性能的分布式信息系統。HTTP/1.1協議包括的許多使緩存盡可能的工作的元素。因為這些元素與協議的其他方面有著千絲萬縷的聯系,而且他們相互作用、影響,因此有必要單獨的來介紹基本的緩存設計。

如果緩存不能改善性能,他將一無用處。HTTP/1.1中緩存的目的是為了在很多情況下減少發送請求,同時在許多情況下可以不需要發送完整響應。前者減少了網絡回路(譯注:一個請求會返回一個響應,請求響應這個過程就是一個回路)的數量;我們利用一個“過期(expiration)”機制來為此目的(見13.2節)。后者減少了網絡應用的帶寬;我們用“驗證(validation)”機制來為此目的。

對行為,可行性,和關閉的操作的要求放松了語義透明性的目的。HTTP/1.1協議允許服務器,緩存,和客戶端能顯示地降低透明性當在必要的時候。然而,因為不透明的操作能混淆非專業的用戶,同時可能和某個服務器應用程序不兼容(例如訂購商品),因此此協議透明性在下面情況下才能被放松要求:

-- 只有在一個顯示的協議層的請求時,透明性才能被客戶端或源服務器放松

-- 當出現一個對終端用戶的顯示的警告時,透明性才能被緩存或被客戶端放松

因此,HTTP/1.1協議提供這些重要的元素:

1.提供完整語義透明的協議特征,當這些特征被通信的所有方需要時

2. 允許源服務器或用戶代理顯示的請求和控制不透明操作的協議特征

3. 允許緩存給這樣的響應綁定警告信息的協議特征,這些響應不能保留請求的語義透明的近似

一個基本的原則是客戶端必須能夠發現語義透明性的潛在的放松。

注意:服務器,緩存,或者客戶端的實現者可能會面對設計上的判斷,而這些判斷沒有顯示地在此規范里討論。如果一個判斷可能會影響語義透明性,那么實現者應該能維持語義透明性,除非一個仔細的完整的分析能說明打破透明性的好處。

13.1.1緩存正確性(Cache Correctness)
一個正確的緩存必須能用最新的響應來響應請求,此響應當在下面的條件滿足時才適合此請求(見13.2.5,13.2.6,和13.12)?

此緩存響應已被檢測與假設通過源服務器重驗證后源服務器返回的響應相等價。

此緩存響應是足夠保鮮(fresh)的(見13.2節)。缺省的情況下,這意味著此響應必須滿足客戶端,源服務器,和緩存的最嚴格的保鮮要求(見14.9節);如果源服務器指定了保鮮壽命,這說明它是源服務器自己的保鮮要求。

由于客戶端和源服務器的最嚴格的保鮮要求,如果一個緩存的響應不是足夠保鮮的,那么在仔細考慮的情況下,緩存可能仍然返回此緩存的響應通過合適的Warning頭域(見13.1.5和14.46節),除非此響應被阻止(例如:通過”no-store” cache-directive ,或者通過一個”no-cache”cache-request-directive;見14.9節)。

此緩存響應是一個304(沒有被改變),305(代理重定向),或 錯誤(4xx或者5xx)響應消息。

如果緩存不能同源服務器通信,那么一個正確的緩存應該用它緩存的響應去響應請求,如果此緩存的響應能正確的服務于請求;如果不能服務器于此請求,那么緩存必須能返回一個錯誤或警告指示存在通信失敗。

如果緩存從服務器端接收到一個響應(或者是一個完整的響應,或者一個304(沒有被改變)的響應),此響應應該是正常情況下要發送到請求的客戶端的,并且此響應并不是新鮮的,那么此緩存應該把此響應轉發給請求客戶端不需要添加一個新的Warning頭域(但是沒有移去已經存在的Warning頭域)。緩存并不是簡單的因為傳輸中響應變得陳舊而嘗試去重驗證響應;這可能會導致一個無限的循環。用戶代理接收一個陳舊的沒有Warning頭域的響應應該提示用戶一個警告信息。

13.1.2警告信息(Warnings)
無論何時,緩存返回一個響應,此響應既不是第一手的(first-hand)也不是足夠保鮮(在13.1.1節的條件2),那么緩存必須利用一個Warning常用頭域來警告產生的效果。Warning頭域和當前定義的警告在14.46節里描述。這些警告允許客戶端去采取合適的動作。

警告可能被用于其他的目的,和緩存相關的目的和其他的目的。警告和錯誤狀態碼的區別在于是否是真正的失敗。

警告被賦予三位數字warn-codes。第一個數字指明:警告是否必須或不必須從緩存項里刪除,在一個成功的重驗證之后。

1xx 警告描述了響應的保鮮或重驗證狀態信息,并且這些信息應該在一個成功的重驗證之后刪除。1xx警告碼可能是由緩存產生的,當緩存驗證一個緩存項時。此警告碼不能被客戶端產生。

2xx 警告描述了實體主體或實體頭域的某些方面的信息,這些信息不能被重驗證修改,并且這些信息不能在一個成功重驗證之后被刪除。

見14.46節關于警告碼的定義。

HTTP/1.0緩存將緩存所有響應中的警告,并且不會刪除第一類警告。穿過HTTP/1.0緩存響應中的警告會攜帶一個額外的warning-date域,這是為了防止將來的HTTP/1.1接收端信任一個錯誤的緩存警告。

警告同樣攜帶一個警告文本。此文本可能是任何合適的自然語義(可能基于客戶端請求的Accept頭域),同時包含一個可選擇的關于何種字符集被使用的聲明。

多個警告可能會綁定一個響應(或者被源服務器或者被一個緩存發送的),這包括多個警告可以共用一個警告碼。例如,服務器可能會以英語和法語提供相同的警告。

當多個警告綁定一個響應時,有時候不可能把所有的警告都展示給客戶。HTTP版本不能指定一個嚴格的優先值去決定警告的優先和順序顯示,但是可以探索一些方法。

13.1.3緩存控制機制 (Cache-control Mechanism)
HTTP/1.1基本的緩存機制(服務器指定過期時間和驗證器)對緩存是隱含的指令。某些情況下,服務器或客戶端可能需要給HTTP緩存提供顯示的指令。我們利用Cache-Control頭域為此目的。

Cache-Control頭域允許客戶端或服務器在請求或響應里傳輸多個指令。這些指令常常覆蓋缺省的緩存算法。作為一個常用規則,如果頭域值中存在一個明顯的沖突,那么最具嚴格解釋的頭域值會被應用(也就是說,能保留語義透明性的值)。然而,一些情況下,cache-control指令被顯示地指定用來削弱語義透明性的相似性(例如,”max-stale” 或者 “public”)。

Cache-control指令在14.9節被描述。

13.1.4顯示的用戶代理警告(Explicit User Agent Warnings)
很多用戶代理允許用戶覆蓋基本緩存機制。例如,用戶代理可能允許用戶指定緩存實體(即使實體明顯是陳舊的)從來不要被驗證。或者,用戶代理可能習慣于給任何請求加上“Cache-Control:max-stale=3600”。用戶代理不能缺省的執行不透明行為,或者不能缺省的執行導致非正常的無效率的緩存行為,但是可能被顯示地設置去這樣做通過一個顯示的用戶動作。

如果用戶已經覆蓋基本的緩存機制,那么用戶代理應該給用戶指示何時顯示不能滿足服務器透明要求的信息(特別地,如果顯示的實體被認為是陳舊的)。因為此協議通常允許用戶代理去判定響應是否是陳舊或不是陳舊的,所以此指示只需要當實際發生時顯示。此指示不必是對話框;它應該是一個圖標(例如,一個正在腐爛的魚)或者一些其他的指示器。

如果用戶以一種方式已經覆蓋了緩存機制,這種方式可能不正常地減少緩存效率,那么用戶代理應該繼續指示用戶的狀態(例如,通過一個圖片顯示)以便用戶不能不注意地消費過度的資源或者忍受過度的延遲。

13.1.5規則和警告的例外情況
在某些情況下,緩存的操作者應該設置緩存返回陳舊的響應,即使此響應沒有被客戶端請求。這個判定本來不應該輕易決定,但是由于某些原因可能會這樣做,特別是當緩存和源服務器連接不好時。無能何時當緩存會返回一個陳舊的響應時,緩存必須給此響應做個標記(利用Warning頭域),因為這樣能使客戶端提示用戶響應是陳舊的。

用戶代理照樣能采取步驟去獲得第一手的或保鮮的響應。由于這個原因,如果客戶端顯示地請求第一手的或保鮮的響應,緩存就不能返回一個陳舊的響應,除非由于技術或策略方面的原因。

13.1.6由客戶控制的行為(Client-controlled Behavior)
當源服務器是過期信息得主要來源時,有時候客戶端可能需要控制緩存去判定是否返回一個緩存響應而不需要緩存通過服務器驗證它。客戶端通過利用一些Cache-Control頭域來達到此目的。

客戶端的請求可能會指定自己愿意接受一個沒有驗證的響應的最大的年齡(age);指定0值會強迫緩存重驗證所有的響應。客戶端照樣會指定在響應過期前的最小保持時間。這些選項增加了對緩存行為的限制,同時這樣做并不能進一步地放松緩存語義透明的近似。

客戶端可能照樣會指定它會接受陳舊響應直到陳舊數達到最大數量。這放松了對緩存的限制,同時這可能違反了源服務器指定對語義透明性的限制,但是這可能支持無連接的操作或者高獲得性當連接不好時。

13.2 過期模型 (Expiration Model)
13.2.1 服務器指定模型(Server-Specified Expiratiion)?
HTTP緩存會工作的很好,這是因為緩存能完全地避免客戶端對源服務器的請求。避免對源服務器請求的主要機制是服務器將來會提供一個顯示過期時間(explicit expiration time),此顯示過期時間用來指示響應可能會滿足后續的請求。也就是說,客戶端請求響應時,緩存能返回一個保鮮(fresh)的響應而不需要從源服務器那里獲得。

我們希望服務器給響應設置顯示過期時間(explicit expiration time),服務器相信在過期時間之前實體不會改變。這能保持語義透明性(譯注:語義透明性情況1.3節里關于“語義透明”的解釋),只要服務器對過期時間仔細選擇。

過期機制只能應用于能從緩存獲得的響應,不能應用于客戶端請求的第一手(first-hand,見1.3節術語)的響應。

如果源服務器希望強制一個語義透明緩存去驗證每個請求,它會使顯示過期時間(explicit expiration time)設為過去。這就是說響應總是陳舊的,所以此緩存應該驗證此響應當緩存利用此響應去服務于后續的請求時。見14.9.4節,有更多強迫重驗證的方法

如果源服務器希望強迫任何HTTP/1.1緩存(不管此緩存是怎樣設置的)去驗證每一個請求,源服務器應該在Cache-Control頭域里指定“must-revalidate”緩存控制指令(見14.9節)。

源服務器利用Expires頭域或在Cache-Control頭域里通過max-age緩存控制指令,來指定顯示過期時間(explicit expiration time)。

過期時間不能被用于強制客戶代理去重新刷新它的顯示或重載資源;過期的語義只能應用于緩存機制,并且這個機制值只需要檢測資源的過期狀態當請求那個資源的一個新請求發生時。見13.13節,關于緩存和歷史機制的區別。

13.2.2 啟發式過期
因為源服務器不能總是提供一個顯示過期時間(explicit expiration time),HTTP緩存通常會設置一個啟發式過期時間(heuristic expiration time),它采用一種算法,此算法利用其它的值(例如Last-Modified時間)去估計一個似乎合理的過期時間。HTTP/1.1規范沒有提供特定的算法,但是的確是加強了對這些算法結果的最壞情況的限制。因為啟發式過期時間可能會對語義透明性妥協,他們本應該被謹慎地使用,并且我們鼓勵源服務器盡可能提供顯示過期時間。

13.2.3 年齡(Age)計算
為了了解緩存項(譯注:緩存項是用來響應請求的,它包含緩存的響應實體)是否是保鮮的(fresh),緩存需要知道其年齡是否已超過保鮮壽命(freshness lifetime)。我們在13.2.4節中討論如何計算保鮮壽命,本節討論如何計算響應或緩存項的年齡。

在此討論中我們用“now”來表示主機進行計算時時鐘的“當前值”。使用HTTP協議的主機,特別是運行于源服務器和緩存的主機,應該使用NTP[28] 或其他類似協議來將其時鐘同步到一個全球性的精確時間標準上。

HTTP1.1協議要求源服務器盡可能在發送每條響應時都附加一個Date頭域,要盡可能在每個響應里給出響應產生的時間(見14.18節)。我們利用術語“date_value”去表示Date頭域的值,這是一種適合于運算操作的表示方法。

當從緩存里獲取響應消息時,HTTP/1.1利用Age響應頭域來傳送響應消息的估計年齡。Age響應頭域值是緩存對響應從產生或被重驗證開始到現在的時間估計值。

實際上,年齡的值是響應從源服務器途徑每一個緩存的逗留時間的總和,再加上響應在網絡路徑上傳輸的時間。

我們用“age_value”來表示Age頭域的值,這是一種適于算術操作的表示方法。

一個響應的年齡(age)可以通過兩種完全不同的途徑來計算::

如果本地時鐘與源服務器時鐘同步的相當好,則用 now - date_value ,若結果為負,則取零。

如果途徑響應路徑(response path)的所有緩存均遵循HTTP1.1協議,則用age_value。

如果我們有兩種獨立的方法計算響應的年齡(譯注:注意這里是響應的年齡),我們可以合并二者如下:

corrected_received_age = max(now – date_value,age_value)?

并且只要我們或者有同步的時鐘或者響應途徑的所有緩存遵循HTTP/1.1,我們就能得到一個可信賴的結果。

由于網絡附加延時,一些重要時隙會在服務器產生響應與下一個緩存或客戶端接收之間流逝。如果不經修訂,這一延遲會帶來不正常的低年齡。

由于導致產生年齡值的請求(譯注:就是存在Age頭域的請求)是早于年齡值的產生,我們能校正網絡附加延遲通過記錄請求產生的時間。然后,當一個年齡值被接收后,它必須被解釋成相對于請求產生的時間,而不是相對響應接收的時間。不管有多少延遲,此算法會導致穩定的結果。所以,我們計算:?

corrected_initial_age = corrected_received_age + (now - request_time)

這里“request_time”是請求的發送時間。

緩存收到響應時,它計算響應年齡的算法如下:

/*?

* 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); //緩存收到響應時響應的年齡

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; //即收到響應到現在的時間間隔

current_age = corrected_initial_age + resident_time;?

緩存項(cache entry)的current_age是緩存項從被源服務器最后驗證開始到現在的時間間隔(以秒記)加上corrected_initial_age。當從緩存項里產生一條響應時,緩存必須在響應里包含一個Age頭域,它的值應該等于緩存項的current_age值。

Age頭域出現在響應里說明響應不是第一手的(first-hand)(譯注:第一手的說明,響應是直接來自于源服務器到達接收端的,而不是來自于緩存里保存的副本)。然而相反的情況并不成立,因為響應里缺少Age頭域并不能說明響應是第一手的(fisrt-hand),除非所有請求路徑上的緩存都遵循HTTP/1.1協議(也就是說,以前HTTP版本緩存沒有定義Age頭域)。?

13.2.4 過期計算(Expiration Calculations)
為了確定一條響應是保鮮的(fresh)還是陳舊的(stale),我們需要將其保鮮壽命(freshness lifetime)和年齡(age)進行比較。年齡的計算見13.2.3節,本節講解怎樣計算保鮮壽命,以及判定一個響應是否已經過期。在下面的討論中,數值可以用任何適于算術操作的形式表示。?

我們用術語“expires_value”來表明Expires頭域的值。我們用術語“max_age_value”來表示Cache-Control頭域里“max-age”控制指令的值(見14.9.3節)。

max-age指令優于Expires頭域執行,所以如果max-age出現在響應里,那么定義如下:

freshness_lifetime = max_age_value?

否則,若Expires頭域出現在響應里,定義如下:

freshness_lifetime = expires_value - date_value?

注意上述運算不受時鐘誤差影響,因為所有信息均來自源服務器。?

如果Expires, Cache-Control:max-age, 或 Cache-Control:s-maxage (見 14.9.3) 均未在響應中出現,且響應沒有包含對緩存的其他控制,那么緩存可以用啟發式算法計算保鮮壽命(freshness lifetime)。緩存器必須對年齡大于24小時的響應附加113警告,如果此響應不帶這種警告。

而且,如果響應有最后修改時間,啟發式過期值應不大于從那個時間開始間隔的某個分數。典型設置為間隔的10% 。

計算響應是否過期非常簡單:

response_is_fresh = (freshness_lifetime > current_age)

13.2.5澄清過期值(Disambiguation Expiration Values)
由于過期值很容易被設置,有可能兩個緩存會包含同一資源的不同保鮮值。

如果客戶端執行請求接收到一個非第一手的響應,此響應在此客戶端擁有的緩存里仍然是保鮮的,并且緩存里的緩存項里的Date頭域的值比此新響應的Date頭域值要新,那么客戶端應該忽略此響應。如果這樣,它可能會重新以“Cache-Control:max-age=0”指令(見14.9節)請求去強制任何中間緩存通過源服務器對其進行檢查。

如果緩存對有不同驗證器(validator)的同一個表現形式(representation)有兩個保鮮響應,那么緩存必須利用Date頭域值最近的響應。這種情況可能發生由于緩存會從其他緩存得到響應,或者由于客戶端請求對一個保鮮緩存項的重載或重驗證(revalidation)。

13.2.6澄清多個響應(Disambiguating Multiple Response)
因為客戶端可能收到經多個路徑而來的響應,所以有些響應會經過一些緩存,而其他的響應會經過其他的緩存,客戶端收到響應的順序可能與源服務器發響應的順序不同。我們希望客戶端利用最新的響應,即使舊響應仍然是保鮮的。

實體標簽(entity tag)和過期值都不能影響響應的順序,因為可能會出現晚一點的響應可能會故意攜帶過早的過期時間。日期值的精度被規定只有一秒。?

當客戶端試著重新驗證一個緩存項的時候(譯注:這里的客戶端應該包含一個本地緩存),而且接收到的響應的Date頭域晚于已存在的緩存項,那么客戶端應該重新進行無條件請求,并且包含

Cache-Control: max-age=0?

去強制任何中間緩存通過源服務器來驗證(validate)這些中間緩存的副本,或者

Cache-Control: no-cache?

去強制任何中間緩存去從源服務器獲得一個新的副本。

13.3 驗證模型(Validation Model)
當緩存有一個舊緩存項并且緩存想利用此緩存項來作為客戶端請求的響應時,緩存必須首先通過源服務器(或者可能通過一個有保鮮響應的中間緩存)對其進行檢驗看看此緩存項是否可用。我們稱做“驗證(validating)”此緩存項。因為我們不想對完整響應的傳輸付出太大代價,而且如果緩存項無效時也不會產生額外的回路(譯注:回路的意思,如:從請求到響應就一條回路),HTTP1.1協議支持使用條件方法。.?

協議支持條件方法的關鍵特征是圍繞“緩存驗證器(cache validator)”展開的。當源服務器產成一個完整響應時,它同時會附加一些驗證器給響應,這些驗證器和緩存項一起保存。當客戶端(用戶代理或緩存服務器)對對應有緩存項的資源執行條件請求時,客戶端包含一個相關的驗證器(validator)在請求里。

服務器(譯注:服務器可能是緩存服務器)則核對請求里的驗證器和當前本地的驗證器是否匹配,如果他們匹配(見13.3.3),則返回一個特定狀態碼(通常為304(沒有改變))的響應并且此響應不包含實體主體(entity body)。如果不匹配,服務器就返回完整響應(包含實體主體)。這樣,我們就避免了傳輸完整響應如果驗證器匹配,同時我們也避免了額外的回路如果驗證器不匹配。

在HTTP1.1協議中,一個條件請求和普通的請求差不多,除了條件請求攜帶一些特殊的頭域(這些頭域包含驗證器),包含這些特殊的頭域隱含地表明請求方法(通常是GET方法)為條件請求方法。

協議中包括緩存驗證條件的正和負。也就是說請求方法將會執行如果驗證器的匹配或不會執行如果驗證器不匹配。

注意:缺少驗證器的響應可能會被緩存,而且會被緩存用來為請求提供服務直到緩存的副本過期,除非顯示地用緩存控制指令來禁止緩存這樣做。然而,緩存不能執行條件方法獲取資源如果它沒有此資源實體的驗證器,那意味著緩存副本將會不可更新在它過期后。?

13.3.1最后修改日期 (Last-Modified Dates)
Last-Modifed實體頭域值經常被用作一個緩存驗證器。簡而言之,緩存項被認為是有效的如果實體自從Last-Modifed值之后沒有改變。?

13.3.2 實體標簽緩存驗證器(Entity Tag Cache Validators)
ETag響應頭域值是實體標簽,它提供了一個“不透明(opaque)的緩存驗證器。這能得到更可靠的驗證當在不方便存放修改日期的情況下,當在HTTP日期值的一秒精度不能滿足需要的情況下,或當在源服務器希望避免使用修改日期產生的沖突的情況下。

實體標簽在3.11節描述了。使用了實體標簽的頭域在14.19,14.24,14.26和14.44節里描述了。

13.3.3 強,弱驗證器 (Weak and Strong Validators)
由于源服務器和緩存會比較兩個驗證器來確定他們是否代表相同的實體,所以通常希望實體(entity,實體主體或實體頭域)發生任何變化時驗證器也相應變化,這樣的驗證器為強驗證器。.?

然而,可能存在這樣的請求,服務器傾向于僅在實體發生重要的語義變化時才改變驗證器,而在實體的某些方面不發生重大改變時就不改變驗證器。在資源變化時驗證器未必變化的稱為弱驗證器.。

實體標簽通常是強驗證器,但協議提供一種機制來使實體標簽變成弱驗證器。可以認為強驗證器在實體的每一字節變化時而變化,而弱驗證器僅在實體的語義變化時才變化。換言之,我們能認為強驗證器是特定實體的標識,而弱驗證器是同一類語義等價實體的標識。

注: 強驗證器的例子:一個整數他會隨著每次實體發生變化而遞增。一個實體的修改時間,如果以秒為精度,能被當作弱驗證器,因為在一秒內資源可能改變兩次。是否支持弱驗證器是選擇的。然而,弱驗證器可以能高效的去緩存等效對象。

.?

客戶端產生請求并把驗證器包含在一個驗證頭域里的時候或在服務器比較兩個驗證器的時候均用到驗證器。強驗證器可在任何情況下使用,而弱驗證器僅在不依賴嚴格相等時才可用。當客戶端產生條件GET請求來請求一個完整實體時,任何類型的驗證器都可以使用。然而,子范圍(sub-range)請求時只能使用強驗證器,因為客戶端可能會得到一個不一致的實體。

客戶端可以在發出簡單(非子范圍)GET請求里既可以包含弱驗證器也可以包含強驗證器。客戶端不能利用弱驗證器在其它的請求形式里。

HTTP1.1協議定義驗證的唯一功能就是比較。有兩種驗證器的比較方法,這依賴于是否能利用弱驗證器進行比較。

.?

- 強比較方法:在考慮相等的情況下,兩驗證器必須完全一致,并且兩個驗證器都是強驗證器。.?

- 弱比較方法:在考慮相等的情況下,兩驗證器必須完全一致,但至少有一個驗證器可能在不影響結果的情況下被標明為“weak”。

實體標簽是強驗證器除非它被顯示地標記為弱(weak)的。3.11節給出了實體標簽的語法。

最后修改時間(譯注:Last-Modifed頭域的值)被用作請求的驗證器時默認為弱驗證器,,除非滿足下列規則才判定它是強驗證器:.?

- 驗證器被源服務器用來和當前實體的驗證器進行比較并且源服務器知道相關的實體不會在當前驗證器函蓋的秒數內改變兩次,

或者

- 驗證器可能被客戶端用于If-Modified-Since 或者 If-Unmodified-Since頭域里,因為客戶端有一個關于此實體的緩存項,并且

- 緩存項包含一個日期值,此日期值給出了源服務器發送源響應(譯注:源服務器產生的響應)的時間,并且

- Last-Modifed頭域值至少提前于日期值(Date頭域值)60秒。?

或者

- 驗證器已經被中間緩存同此實體的緩存項里的驗證器比較過 ,并且

- 緩存項包含日期值(Date頭域值),此日期值指明了源服務器發送源響應的時間,并且

- Last-Modifed頭域值至少提前于日期值(Date頭域值)60秒。

此種方法依賴于以下事實,如果兩個響應被服務器在同一秒內被發出,但這兩個響應都有相同的最后修改(Last-Modified)時間,那么至少有一個響應的日期值(譯注:Date頭域的值)和最后修改時間值(Last-Modifed頭域的值)是相等的。60秒的限制能保證Date和Last-Modifed頭域的值在不同時刻產生。一個實現可能會利用大于60秒的值,如果它認為60秒太短。

如果客戶端希望執行子范圍(sub-range)請求來請求一個只有最后修改(Last-Modifed)時間和而沒有透明驗證器的值時,它可能會認為只有最后修改(Last-Modified)時間是強的。

若緩存或源服務器收到一個條件請求,而不是得到完整響應的GET請求時,他必須使用強比較方法去計算此條件。

此規定允許HTTP1.1的,緩存和客戶端安全地執行子范圍(sub-range)請求來請求從HTTP/1.0得來的值。?

13.3.4 關于何時使用實體標簽和最后修改時間的規則
我們對源服務器,客戶端和緩存采用一套規則和建議來規定不同的驗證器何時應該被使用,出

于何種目的被使用。

HTTP/1.1 源服務器:

- 應該發送一個實體標簽驗證器除非源服務器產生這樣一個實體標簽不可行。

- 可能會發送弱實體標簽而不是強實體標簽,如果使用弱實體標簽能提高性能的話或者如果發送一個強實體標簽不可行的情況下。

- 應該發送一個Last-Modifed值如果可行的話,除非打破語義透明性(這可能由利用If-Modified-Since頭域里的日期產生)可能會導致嚴重的后果。

換句話說,對http1.1源服務器來說,比較好的做法是同時發送強實體標簽和Last-Modified值。.?

為了合法,強實體標簽必須隨相關聯的實體值改變而改變。弱實體標簽應該隨相關聯的實體在語義上發生改變而改變。

注意:為保證語義透明緩存,源服務器必須避免為兩個不同的實體重復利用一個特定的強實體標簽值。緩存項應該能保持任意長的時間,而不管過期時間(expiraton time),所以緩存可能會再去嘗試去利用在過去某一時刻獲得的驗證器去驗證緩存項。?

HTTP/1.1 客戶端:?

- 若實體標簽被源服務器提供,HTTP/1.1客戶端必須在任何緩存條件請求(利用了If-Match或If-None-Match的請求)里利用實體標簽.。

- 僅當Last-Modified值被源服務器提供時,HTTP/1.1客戶端應該在非子范圍緩存條件請求(利用If-Modified-Since)里利用此值。?

- 僅當Last-Modified值被HTTP/1.0源服務器提供,HTTP/1.1客戶端可能會在子范圍緩存條件請求(利用了If-Unmodified-Since)里利用此值。

- 如果一個實體標簽和Last-Modified值被源服務器提高,HTTP/1.1客戶端應該在緩存條件請求里利用這兩個驗證器。這允許HTTP/1.1和HTTP/1.1緩存能合適地進行響應。?

HTTP/1.1源服務器,當接收到一個條件請求并且此請求同時包含Last-Modifed日期(例如,在If-Modified-Since,或If-Unmodified-Since頭域里)和一個或多個實體標簽(例如在If-Match,If-None=Match,或If-Range頭域里)作為緩存驗證器時,源服務器不能返回一個304狀態響應(Not Modified)除非這樣做能當當前實體的驗證器和請求里所有的條件頭域里的驗證器一致。

HTTP/1.1緩存服務器,當接收到一個條件請求并且此請求里同時包含Last-Modified日期和一個或多個實體標簽作為緩存驗證器時,它不能返回一個本地的副本給客戶端除非那個副本的驗證器和所有請求里條件頭域里的驗證器一致。

注意:這些規則背的常用的原則是HTTP/1.1服務器和客戶端應該在請求和響應里盡可能傳輸非冗余的信息。接收這些非冗余信息的HTTP/1.1系統將會假設它接收了驗證器。

HTTP/1.0客戶端和緩存將會忽略實體標簽。通常,Last-Modified值被這些系統接收后將會保證透明和高效的緩存行為,所以HTTP/1.1源服務器這時將會提供Last-Modified值。在這些情況下,當HTTP/1.0系統利用一個Last-Modified值作為一個驗證器可能會帶來嚴重的后果時,HTTP/1.1服務器將不會提供Last-Modified值。

13.3.5非驗證條件(Non-validating Conditionls)
實體標簽背后的原則是只有服務的作者才知道資源的語義而去選擇一個合適的緩存驗證機制,并且任何驗證器比較方法的標準都可能會帶來風險。所以,任何其他的頭域的比較(除了Last-Modified,為了兼容HTTP/1.0)從來不會被用于驗證緩存項。

13.4 響應的可緩存性(Response Cacheability)
除非被緩存控制(見14.9節)指令明確地限制,緩存系統可以將一成功的響應作為緩存項,可以返回緩存項里的響應副本而不需要驗證它如果此副本是保鮮的,并且也可以在驗證成功后返回它。如果既沒有和響應相關的緩存驗證器也沒有和響應相關的顯示過期時間(explicit expiration time,譯注:見13.3.1節里關于什么是顯示過期時間的說明),我們不會認為它是可緩存的,但是某些緩存可能會違反這個期望(例如,當不能進行網絡連接時)。客戶端能經常發現從緩存里獲得的響應,只需要通過把Date頭域值同當前時間作比較。

注意:某些HTTP1.0緩存可能違反這一期望而不提示警告。

還有,某些情況下可能不便保留一實體,或將其返回給后續請求.?

然而,在一些情況下,緩存不適合保存一個實體,或者不適合把它放于后續請求的響應里。這可能因為服務作者認為完全語義透明性是有必要的,或著因為安全和隱私的考慮。某些緩存控制指令是為了讓服務器能指明某些資源實體或其中的一部分不能被緩存。

注意在14.8節里描述了防止一個共享緩存去保存和返回一個以前請求的響應,如果那個請求包含一個Authorization頭域。

除非緩存控制指令防止此響應被緩存,一個接收的響應如果它的狀態碼是200,203,206,300,301或410,那么此響應應該被緩存保存而且可用于后續的請求,但這必須受限于過期機制(expiration mechanism)。然而,緩存如果不支持Range和Content-Range頭域,那么它不能緩存206響應(部分內容)響應。

接收到的響應如果是其他的狀態碼(如,302和307),那么此響應不能被用于服務于后續的請求,除非緩存控制指令或其他的頭域明確地允許它能這樣做。例如,這些頭域包含下面的頭域:Expires頭域(見14.21);“max-age”,“s-maxage”,“must-revalidate”,“prox-revalidate”,“public”或“private”緩存控制指令(見14.9)。

13.5 從緩存里構造響應
緩存的目的是存儲請求的響應信息,為了響應將來的請求。在很多情況下,緩存能返回響應的合適部分給請求者。然而,如果緩存擁有一個基于以前響應的緩存項,它可能必須把新響應的部分和它緩存項里的內容合起來。

13.5.1End-to-end和Hop-by-hop頭域
為定義緩存和非緩存代理服務器的行為,我們將HTTP頭域分成兩類:

- end-to-end頭域,他們被傳輸給最終請求或響應的接收者。響應里end-to-end頭域必需作為緩存項的一部分存儲,并且必須在從緩存項形成的響應里傳輸。

- hop-by-hop頭域,他們被只對傳輸層上的連接有意義,并且不能被緩存保存或被代理轉發。

下面的HTTP/1.1頭域是hop-by-hop頭域:

- Connection

- Keep-Alive

- Proxy-Authenticate

- Proxy-Authorization

- TE

- Trailers

- Transfer-Encoding

- Upgrade

所有其他被HTTP/1.1定義的頭域均為end-to-end頭域。

13.5.2不可更改的頭域 (Non-modifiable Headers)
HTTP1.1的某些特征,如數字認證,基于某一些end-to-end頭域。一個透明代理不應該改變end-to-end頭域,除非這些頭域的定義要求或允許它這樣做。

一個透明代理(譯注:代理一般是緩存,緩存可以叫緩存代理,緩存服務器,代理服務器)不能改變請求或響應里的下面的頭域,而且它不能添加這些頭域到沒有這些頭域的請求或響應里:

- Contents-location

- Content-MD5

- ETag

- Last-Modified

一個透明代理不能改變響應里下面的的頭域:?

- Expires?

但它可以添加這些頭域如果響應里沒有這些頭域的時候。如果一個Expires頭域被添加,它必須等于響應里Date頭域的值。

一個代理(譯注:緩存就是一個代理,我們一般稱做緩存代理,或緩存服務器,或緩存代理服務器,都是一個意思)不能在消息中改變或添加下面的頭域如果此消息包含no-transform緩存控制指令,或在任何請求里也不能添加或改變這些頭域。

- Content-Encoding?

- Content-Range?

- Content-Type?

一個非透明代理可能會改變或添加這些頭域給一個消息如果此消息不包含no-transform緩存控制指令,但是如果代理這樣做了,它必須添加一個警告214(轉換被應用)(見14.46節)。

警告:end-to-end頭域的不必要的改變可能會導致認證機的失敗如果更強的認證機制被應用于后續的HTTP版本中。此認證機制可能依賴于沒有在此出現的頭域值。

請求或響應里的Content-Length頭域被添加或被刪除會根據4.4節的規則。一個透明代理必須保留實體主體的entity-length(見7.2.2),盡管它可以可能改變transfer-length(4.4節)。

13.5.3聯合頭域(Combining Headers)
當一個緩存對服務器發出驗證請求時,而且服務器提供304(沒有改變)響應或206(部分內容)響應時,那么緩存將構造一個響應發送給請求客戶端。

如果狀態碼是304(沒有改變),緩存利用緩存項里的實體主體(entity-body)作為客戶端請求響應的實體主體。如果響應狀態碼是206(部分內容)并且Etag或Last-Modified頭域能精確匹配,那么緩存可能把存入緩存項里的內容和接收到的響應里的新內容合并并且利用最后合并的結果作為輸出響應(見13.5.4)。

存儲于緩存項里端end-to-end頭域被用于構造響應,除了:

- 任何存儲的警告碼是1xx(見14.46)Warning頭域必須從緩存項和轉發的響應里刪除。

- 任何存儲的警告碼是2xx的Warning頭域必須要在緩存項和轉發的響應里保留。

- 任何在304或206響應里的end-to-end頭域必須替換緩存項里相應的頭域

除非緩存決定去刪除緩存項,否則它必須照樣能用接收的響應里的相應的end-to-end頭域去替換存儲在緩存項里的頭域,除了上面描述的Warning頭域。如果輸入響應里的一個頭域匹配緩存項里多個頭域,那么所有這些舊的頭域必須被替換。

從另一方面說,輸入響應的所有end-to-end頭域會覆蓋緩存項里所有相應的end-to-end頭域(除了緩存的警告碼是1xx的Warning頭域,它將會被刪除即使沒有被覆蓋)。

注意:此規則允許源服務器去利用304(沒有改變)或一個206(部分內容)響應去更新任何同一實體或實體的子范圍的以前響應的頭域,雖然它可能沒有意義或這樣做不正確。這條規則不允許源服務器去利用304(沒有改變)或206(部分內容)響應去完全地刪除一個以前響應的頭域。

13.5.4聯合字節范圍(Combing Byte Ranges)
一條響應可能僅傳送一個實體主體的某一部分,這是由于請求包含一個或多個Range指定的范圍,或者由于連接會被過早地斷開。在幾次這樣得傳輸后,緩存可能已經接收了同一個實體主體的多個范圍部分。

如果緩存有一個實體的非空子范圍,并且一個輸入(incoming)響應(譯注:輸入響應是進入緩存的響應,輸出響應是從緩存出去的響應)攜帶了另一個子范圍,那么緩存可能會把新的子范圍和已經存在的子范圍聯合起來如果兩者遵循下面的規則:

- 輸入響應和緩存項都有緩存驗證器。

- 當利用強比較方法的時候,兩個緩存驗證器完全匹配(見13.3.3)。

如果任何一個要求不能滿足,緩存必須利用最近的部分響應(這基于任何響應的Date頭域值,并且會利用輸入響應如果這些Date頭域值相等或丟失了),而且必須丟棄其他的部分信息。

13.6 緩存已經協商過的響應(Caching Negotiated Responses)
在Vary頭域出現在響應里的時候,服務器驅動內容協商(12.1節)的使用會改變緩存利用響應去響應后續請求利用的條件和過程。見14.44節關于服務器利用Vary頭域的描述。

服務器應該利用Vary頭域去通知一個緩存什么樣的請求頭域應該被使用從而從一個可緩存的并受限于服務器驅動協商的響應的多個表現形式中選擇合適的表現形式。Vary頭域里指定的頭域被稱做選擇請求頭域(selecting request-header)。

當緩存接收到一個后續的請求,此請求的URI對應一個或多個包含了Vary頭域的緩存項時,此緩存不能利用這樣一個緩存項去構造出一個響應去服務于新來的請求,除非所有出現在新請求里的選擇請求頭域匹配存儲在源請求里被存儲的請求頭域。

在兩個請求里,我們定義這兩個選擇請求頭域匹配,如果并且只有第一個請求的選擇請求頭域能被轉換為第二個請求里的頭域通過添加或刪除線性空白(被允許出現在相應的BNF里的線性空白)和/或把多個消息頭域結合成一個頭域通過4.2節里的規則。

一個Vary頭域值是“*”總是不能匹配的,并且后續那個資源的請求只能合適地被源服務器解析。

如果緩存項里的選擇請求頭域(selecting request-header)不能匹配新請求的選擇請求頭域,那么緩存不能利用緩存項去滿足請求除非它能以一個條件請求把此新請求接力到源服務器并且此源服務器以一個304(沒有改變)的狀態碼進行響應并包含一個實體標簽或者Content-Location頭域指明將要被使用的實體。

如果一個實體標簽被賦予一個緩存的表現形式,那么此轉發的請求將是條件的并且所有那個資源的緩存項的實體標簽將會被包含于If-None-Match頭域里。這向服務器表達當前緩存擁有的實體集,以至于如果這些實體里的任何實體匹配請求的實體,服務器會利用Etag頭域在304(沒有改變)響應里去告訴緩存哪個緩存項是合適的。如果新響應的實體標簽匹配已經存在的緩存項,那么新響應應該被利用去更新已經存在的緩存項的頭域,而且此結果必須返回給客戶端。

如果任何已經存在的緩存項包含只有相關實體的部分內容,那么此實體的實體標簽不應該被包含在If-None-Match頭域里除非這個請求是為了請求實體的一個范圍,此范圍完全可以被緩存項滿足。

如果緩存接收到一個成功的響應,此響應的Content-Location頭域匹配于已經存在的緩存項的Content-Location頭域對同一請求URI來說,并且此響應的實體標簽不同于已經存在的緩存項的實體標簽,而且此響應的Date頭域值比已經存在的緩存項更近,那么已經存在的緩存項不能被返回去響應將來的請求并且將會從緩存里刪除。

13.7 共享和非共享緩存 (Shared and Non-Shared Caches)
出于安全和保密考慮,有必要區分共享和非共享緩存。非共享緩存是僅供一個用戶使用的緩存,此種情況下,可用性由適當的安全機制控制。所有其它的緩存均被認為是共享緩存。此協議的其它部分給一些對共享緩存的限制以防止隱私丟失或訪問控制的失敗。

13.8 錯誤和不完全的響應緩存行為
緩存收到不完整響應(例如響應的字節數比Content-Length頭域指定的值要小)也可以存儲它,但是必須把它看作部分響應。部分相應可以合并(見13.5.4);合并結果可能是完整的響應或可能仍是部分的響應。.緩存不能把部分響應返回給客戶端除非有明確要求可以這樣做例如利用206(部分內容)狀態碼響應。緩存不能使用一個200(OK)狀態碼返回一個部分響應。

如果緩存在試圖重驗證一個緩存項而收到一個5xx響應時,它既可以將此響應轉發給請求的客戶端,或者做的就像服務器不能響應似的。在后面的情況下,它可能返回一個以前的接收的響應除非緩存項包含一個“must-revalidate”緩存控制指令(見14.9節)。

13.9 GET 和 HEAD 的副作用(Side Effects of GET and HEAD)
除非源服務器明確地禁止緩存保存它們的響應,對任何資源應用的GET和HEAD方法不應該有副作用,這些副作用會導致錯誤的行為如果這些響應將從緩存產生。他們可能會仍然有副作用,但緩存在決定緩存時不必考慮這些副作用。緩存總是期望去觀察一個源服務器對緩存的明確限制。

一個例外:有些應用習慣于在在GETs和HEADs方法里使用查詢URLs(在rel_path_part里包含一個“?”)去執行一個操作而帶來很大的副作用,緩存不能把此URIs的響應看作一個保鮮的除非服務器提供一個顯示過期時間(explicit expiration time)。這意味著此URIs的以前從HTTP/1.0服務器產生的響應不能來自于緩存。見9.1.1節相關的信息。

13.10 在更新或刪除后的無效性
對源服務器上的某資源執行方法的副作用可能會使一個或多個已經存在的緩存項的不透明性無效。那就是說,雖然他們可能會繼續是保鮮的,但是他們不能準確的反應出源服務器將會對這一個新的請求返回什么。

HTTP協議無法保證所有此類緩存項均被標明無效。例如,引起源服務器上資源變化的請求可能不會穿過存有一個緩存項的代理。然而,一些規則幫助減少錯誤行為的可能。

在此節里,短語“使實體無效”意味著緩存會將所有那個實體的實例從它的存儲里移除,或者把這些實體的實例標記為“無效的”并且在他們可能作為后續請求的響應時會被進行重驗證。?

一些HTTP方法必須讓緩存去使一個實體無效 。這些實體被請求URI指定,或在Location或在Content-Location頭域里被指定(如果出現的話)。這些方法是:

- PUT

- DELETE

- POST

為了防止服務器攻擊拒絕,一個基于Location或Content-Location頭域里的URI的無效性處理必須只有在host部分和請求URI里的host部分相同時才被執行。?

一個緩存如果不能理解請求里的方法,那么它應該使請求URI指定的任何實體無效。

13.11 強制寫通過( Write-Through Mandatory)
所有可能對源服務器資源進行修改的方法都要寫通過給源服務器(譯注:直接穿過緩存在服務器上修改)。這通常包括所有方法除了GET和HEAD方法。緩存在將此種請求轉發給服務器并獲得相應的響應前不能對請求客戶端做出響應。 這個不能防止代理緩存(譯注:也可以叫緩存服務器,緩存)在服務器已經發送最終回復之前發送100(繼續)響應。

相反情況(通常叫“寫回”或“拷貝回”緩存)在HTTP1.1中是不允許的,這是由于提供一致更新非常困難,并且服務器,緩存和網絡的故障會出現在比寫回早。?

13.12 緩存替換 (Cache Replacement)
如果一個新的可緩存的響應被緩存接收,同時對這一資源的響應已經在緩存里存在,那么緩存應該利用最新的響應去回復當前的請求。緩存可能會把此新響應放進存儲里,并且如果它滿足所有其他的要求,緩存將會利用此響應來響應任何將來的請求。如果緩存想把此新的響應加進緩存的存儲,13.5.3的規則必須應用。

說明:一個新響應如果它的Date頭域值比已經存在的緩存響應的Date頭域值老,那么它是不能緩存的。

13.13 歷史列表 (History Lists)
用戶代理經常使用歷史機制,如“Back”按鈕和歷史列表,來重新展示在一個會話里接收的一個稍早的實體。

歷史機制和緩存機制是不同。歷史機制不應該嘗試展示一個當前資源狀態的語義透明視圖。其歷史機制只是為了展示在獲得資源時看到了什么。

默認情況,一個過期時間不會應用于一個歷史機制。如果實體仍然在存儲里,歷史機制應該顯示它即使實體過期了,除非用戶叫用戶代理去刷新過期的文檔。

這不能被解釋去防止歷史機制告訴用戶視圖可能過期了。?

注意:如果歷史機制沒必要地防止了用戶看陳舊的資源,那么這會強制服務作者去避免利用HTTP過期控制和緩存控制。服務作者可能會認為這是非常重要的當用戶沒有被呈現錯誤消息或警告消息當他們利用導向按鈕(如BACK按鈕)去看以前獲得的資源時。即使有時這些資源本不能被緩存保存或應該可能會很快過期,用戶界面可能會強制服務作者去求助于其他防止緩存的方法(例如,一次性URLs)為了避免歷史機制功能的不合適的作用。

總結

以上是生活随笔為你收集整理的HTTP中的缓存的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。