?
This document uses PHP Chinese website manual Release
HTTP具有條件請求 的概念,通過比較受影響的資源和驗證器的值,可以更改結(jié)果,甚至請求的成功。這些請求可用于驗證緩存的內(nèi)容,避免無用的控制,驗證文檔的完整性(例如恢復(fù)下載時),或防止在上載或修改服務(wù)器上的文檔時丟失更新。
HTTP條件請求是執(zhí)行不同的請求,具體取決于特定標(biāo)頭的值。這些頭文件定義了一個先決條件,如果前提條件匹配,請求的結(jié)果將會不同。
不同的行為由所使用的請求的方法以及用于前提條件的一組標(biāo)題定義:
對于通常試圖獲取文檔的安全方法,GET
條件請求可用于發(fā)回文檔(如果相關(guān)的話)。因此,這節(jié)省了帶寬。
對于不安全的方法,例如PUT
通常上傳文檔的情況,條件請求可以用于上載文檔,只有當(dāng)它基于的原始文檔與存儲在服務(wù)器上的文檔相同時。
所有條件標(biāo)題都會嘗試檢查服務(wù)器上存儲的資源是否與特定版本匹配。為了實現(xiàn)這一點,條件請求需要指示資源的版本。由于將整個資源字節(jié)與字節(jié)進行比較是不切實際的,并不總是需要的,所以請求傳輸描述版本的值。這些值稱為驗證器,有兩種:
文檔上次修改日期,即上次修改日期。
一個不透明的字符串,唯一標(biāo)識每個版本,稱為實體標(biāo)簽或etag。
比較相同資源的版本有點棘手:根據(jù)上下文,有兩種相等性檢查:
當(dāng)期望字節(jié)到字節(jié)的身份時,例如在恢復(fù)下載時使用強驗證。
當(dāng)用戶代理只需要確定兩個資源是否具有相同的內(nèi)容時使用弱驗證。即使他們是微小的差異,就像不同的廣告,或不同的日期頁腳。
驗證的類型與所使用的驗證器無關(guān)。雙方Last-Modified
并ETag
允許這兩種類型的驗證,雖然復(fù)雜性來實現(xiàn)它在服務(wù)器端可能會有所不同。HTTP默認(rèn)使用強大的驗證,并指定何時可以使用弱驗證。
強有力的驗證包括保證資源是字節(jié)到字節(jié),與它所比較的資源相同。這對于一些條件標(biāo)頭是必需的,對其他標(biāo)簽是默認(rèn)的。強大的驗證非常嚴(yán)格,可能難以在服務(wù)器級別保證,但它確保在任何時候都不會丟失數(shù)據(jù),有時會犧牲性能。
使用一個獨特的標(biāo)識符來進行強有力的驗證是非常困難的Last-Modified
。通常這是通過使用ETag
資源的MD5散列(或派生)來完成的。
弱驗證與強驗證不同,因為它認(rèn)為如果內(nèi)容是相同的,則文檔的兩個版本是相同的。例如,只有頁腳中的日期不同或其他廣告與另一頁不同的頁面會被視為與驗證較弱的頁面完全相同。這些相同的兩個版本在使用強大驗證時被認(rèn)為是不同的 構(gòu)建一個etags系統(tǒng)會產(chǎn)生弱驗證,這可能很復(fù)雜,因為它涉及了解頁面不同元素的重要性,但對優(yōu)化高速緩存性能非常有用。
一些稱為條件標(biāo)題的HTTP標(biāo)題會導(dǎo)致有條件的請求。這些是:
如果ETag
遙遠(yuǎn)的資源等于此標(biāo)題中列出的資源,If-Match
則成功。默認(rèn)情況下,除非etag帶有前綴'W/'
,否則會執(zhí)行強有力的驗證。If-None-Match
如果ETag
遠(yuǎn)程資源的不同于此標(biāo)題中列出的每個資源,則成功。默認(rèn)情況下,除非etag帶有前綴'W/'
,否則會執(zhí)行強有力的驗證。如果Last-Modified
距離資源的日期比此標(biāo)題中給出的日期更近,If-Modified-Since
則成功。如果Last-Modified
遙遠(yuǎn)資源的日期較舊或與此標(biāo)題中給出的日期相同,If-Unmodified-Since
則成功。If-Range
與If-Match
或類似If-Unmodified-Since
,但可以只有一個單一的etag或一個日期。如果失敗,范圍請求失敗,而不是206Partial Content
響應(yīng)200OK
與完整的資源一起發(fā)送。
條件請求最常見的用例是更新緩存。使用空緩存或無緩存時,請求的資源將以狀態(tài)返回200
OK
。
與資源一起,驗證器將在標(biāo)題中發(fā)送。在這個例子中,無論是Last-Modified
和ETag
發(fā)送,但它同樣一直只是其中之一。這些驗證器會與資源一起緩存(如所有頭文件),并在緩存過期時用于創(chuàng)建條件請求。
只要緩存不陳舊,根本就不會發(fā)出請求。但是一旦它變得陳舊,這主要由Cache-Control
頭部控制,客戶端不直接使用緩存值,而是發(fā)出條件請求。驗證程序的值用作If-Modified-Since
和If-Match
標(biāo)題的參數(shù)。
如果資源沒有改變,服務(wù)器發(fā)回一個304
Not Modified
響應(yīng)。這使得緩存再次變得新鮮,并且客戶端使用緩存的資源。盡管響應(yīng)/請求往返消耗了一些資源,但這比通過線路傳輸整個資源更有效。
如果資源發(fā)生了變化,那么服務(wù)器只是發(fā)送一個200
OK
響應(yīng),并帶有新版本的資源,就像請求不是有條件的并且客戶端使用這個新資源(并對其進行緩存)一樣。
除了在服務(wù)器端設(shè)置驗證器之外,這種機制是透明的:所有瀏覽器管理一個緩存并發(fā)送這樣的條件請求,而不需要Web開發(fā)人員完成任何特殊工作。
文件的部分下載是HTTP的功能,允許恢復(fù)先前的操作,通過保留已獲得的信息來節(jié)省帶寬和時間:
支持部分下載的服務(wù)器通過發(fā)送Accept-Ranges
標(biāo)題來廣播此內(nèi)容。一旦發(fā)生這種情況,客戶端可以通過發(fā)送Ranges
缺少范圍的標(biāo)題來恢復(fù)下載:
原理很簡單,但是存在一個潛在的問題:如果下載的資源在兩次下載之間被修改,則獲得的范圍將對應(yīng)于資源的兩個不同版本,并且最終文檔將被損壞。
為了防止這種情況,使用條件請求。對于范圍,有兩種方法可以做到這一點。如果前提條件失敗,則使用更靈活的If-Modified-Since
和If-Match
和服務(wù)器返回錯誤; 客戶端從頭開始重新下載:
即使此方法起作用,它在文檔發(fā)生更改時也會添加額外的響應(yīng)/請求交換。這會影響性能,并且HTTP有一個特定的頭部以避免這種情況If-Range
::
該解決方案效率更高,但靈活性稍差,因為在該情況下只能使用一個etag。很少需要這種額外的靈活性。
Web應(yīng)用程序中的常見操作是更新遠(yuǎn)程文檔。這在任何文件系統(tǒng)或源代碼管理應(yīng)用程序中都很常見,但任何允許存儲遠(yuǎn)程資源的應(yīng)用程序都需要這種機制。常見的網(wǎng)站,比如維基和其他CMS,都有這樣的需求。
用這個PUT
方法你可以實現(xiàn)這個目的??蛻舳耸紫茸x取原始文件,修改它們,最后將它們推送到服務(wù)器:
不幸的是,只要我們考慮到并發(fā)性,事情就會有點不準(zhǔn)確。當(dāng)客戶端在本地修改資源的新副本時,第二個客戶端可以獲取相同的資源并在其副本上執(zhí)行相同的操作。接下來發(fā)生的事情非常不幸:當(dāng)他們回到服務(wù)器時,第一個客戶端的修改被下一個客戶端推送所拋棄,因為這第二個客戶端并不知道第一個客戶端對資源的更改。誰贏的決定不會傳達給對方。哪些客戶的變化將被保留,會隨著他們提交的速度而變化; 這取決于客戶端,服務(wù)器的性能,甚至是在客戶端編輯文檔的人員。獲勝者將從一次改變到下一次。這是一個競賽條件 并導(dǎo)致難以檢測和調(diào)試的有問題的行為:
如果不打擾兩個客戶之一,就無法處理這個問題。但是,要避免丟失的更新和競賽條件。我們希望得到可預(yù)測的結(jié)果,并期望在客戶的更改被拒絕時通知客戶。
有條件的請求允許實現(xiàn)積極鎖定算法(由大多數(shù)維基或源代碼控制系統(tǒng)使用)。其概念是允許所有客戶端獲得資源副本,然后讓他們在本地修改它,通過成功地允許第一個客戶端提交更新來控制并發(fā)性。所有后續(xù)更新(基于資源的過時版本)都會被拒絕:
這是使用If-Match
或If-Unmodified-Since
頭來實現(xiàn)的。如果etag與原始文件不匹配,或者文件自獲取后已被修改,則更改將被拒絕并出現(xiàn)412
Precondition Failed
錯誤。然后由客戶來處理錯誤:通過通知用戶重新開始(這次是最新版本),或者通過向用戶顯示兩個版本的差異,幫助他們確定他們希望保留哪些改變。
資源的第一次上傳是以前的一個邊緣案例。與資源的任何更新一樣,如果兩個客戶端嘗試在相似時間執(zhí)行,則會受到競爭狀況的影響。為了防止這種情況,可以使用條件請求:通過添加If-None-Match
特殊值'*'
,代表任何etag。只有在資源不存在之前,該請求才會成功:
If-None-Match
將僅適用于HTTP / 1.1(及更高版本)兼容的服務(wù)器。如果不確定服務(wù)器是否符合要求,則需要首先向HEAD
資源發(fā)出請求以檢查該問題。
有條件的請求是HTTP的一個關(guān)鍵功能,并允許構(gòu)建高效和復(fù)雜的應(yīng)用程序。為了緩存或恢復(fù)下載,網(wǎng)站站長只需要正確配置服務(wù)器; 在一些環(huán)境中設(shè)置正確的etags可能會很棘手。一旦實現(xiàn),瀏覽器將滿足預(yù)期的條件請求。
對于鎖定機制,情況恰恰相反:Web開發(fā)人員需要使用正確的標(biāo)題發(fā)出請求,而網(wǎng)站管理員可以主要依靠應(yīng)用程序來執(zhí)行對它們的檢查。
在這兩種情況下,很顯然,有條件的請求是Web背后的基本特征。