Alkaidcc

Alkaidcc

就算失败也没关系:)
jike
twitter
github

什麼是HTTP快取

什麼是 HTTP 快取#

我們為什麼需要快取(cache)?

我們知道,我們每次訪問一個網頁都需要加載資源,如果這些資源都從遠端的伺服器上加載,整個請求和響應時間會很長,有沒有快一點的辦法呢?有,可以從附近的 CDN 請求資源,減少了長距離的網路傳輸,響應速度自然就提升了。可是,CDN 還是離客戶端有點遠,有沒有辦法在瀏覽器快取數據,儘量少的向外請求資源呢?其實這些思想都是快取的思想,在每個節點都做快取就可以極大地減少遠端資源請求,加快響應速度。

web-cache

快取中有幾個概念

web-cache

  • Stale Content:陳舊的內容,即被快取且過期的內容
  • Fresh Content:新鮮的內容,即被快取且未過期的內容
  • Cache Validation:是聯繫伺服器以檢查快取內容的有效性,並在其即將過期時得到更新的過程。
  • Cache Invalidation:是刪除快取中可用的任何陳舊內容的過程。

快取按照位置可以分為瀏覽器快取代理快取反向代理快取

瀏覽器快取#

瀏覽器快取僅限於一個用戶,並且與其他快取不相同,並且它可以存儲私有的響應。

代理快取#

與服務於單個用戶的瀏覽器快取不同,代理快取可以服務於訪問相同內容的數百個不同用戶。往往是由 ISP 實施的。

isp-cache

反向代理快取#

反向代理快取一般部署在伺服器端,用於減輕伺服器的負載。

reverse-proxy

快取頭#

每當伺服器發出一些響應時,它都會伴隨一些 HTTP 標頭,以指導快取與否以及如何快取此響應

Expires#

在 HTTP/1.1 和引入快取控制之前,有一個 Expires 標頭,它只是一個時間戳,告訴快取應該將某些內容視為新鮮的時間。比如

Expires: Mon, 13 Mar 2017 12:22:00 GMT

當然,快取上的時鐘必須與伺服器上的時鐘同步,否則可能無法實現所需的結果。

儘管 Expires 還在使用,但我們現在應該優先考慮Cache-Control

Pragma#

這也是來自 HTTP/1.1 的舊特性,我們可能會看到在這裡和那裡使用Pragma: no-cache,希望阻止響應被快取。

Cache-Control#

快取控制(Cache-Control)規定了內容應被快取多長時間和以何種方式快取。

cache-control 可以包含多個值,

private

將快取設置為私有意味著該內容不會在任何代理中被快取,它只會被客戶端(即瀏覽器)快取。

public

如果設置為公開,除了被客戶端快取外,還可以被代理機構快取;為許多其他用戶服務。

no-store

指定該內容不被任何一個快取所快取。

no-cache

no-cache 表示可以保持快取,但快取的內容在被提供之前要從伺服器上重新驗證(例如,使用 ETag)。也就是說,仍然有一個對伺服器的請求,但是是為了驗證,而不是為了下載快取的內容。

max-age: seconds

max-age 規定了內容被快取的秒數。例如,如果 cache-control 看起來像下面這樣。

cache-control: max-age=900, private

s-maxage: seconds

s-maxage 這裡 s - 前綴代表共享。這條指令專門針對共享快取。像 max-age 一樣,它也可以得到一些東西被快取的秒數。如果存在,它將覆蓋共享快取的 max-age 和 expires 頭文件。

must-revalidate

must-revalidate 有時可能發生的情況是,如果你有網路問題,而內容無法從伺服器檢索,瀏覽器可能會在沒有驗證的情況下提供陳舊的內容。 must-revalidate 可以避免這種情況。如果這個指令存在,意味著在任何情況下都不能提供陳舊的內容,在提供數據之前必須從伺服器上重新驗證。

proxy-revalidate

proxy-revalidate 與 must-revalidate 類似,但它對共享或代理快取的規定是相同的。換句話說,proxy-revalidate 對於 must-revalidate 來說就像 s-maxage 對於 max-age 一樣。

Mixing Values

我們可以以不同的方式組合這些指令以實現不同的快取行為,但是no-cache/no-storepublic/private是互斥的。如果同時指定no-storeno-cache,則no-store將優先於no-cache

Validators#

到目前為止,我們只討論了內容是如何被快取的,以及多長時間的快取內容被認為是新鮮的,但我們沒有討論客戶端如何從伺服器上進行驗證。下面我們討論用於此目的的頭信息。

Etag

Etag 或 "Entity Tag" 是在 HTTP/1.1 規範中引入的。Etag 只是一個獨特的標識符,伺服器將其與一些資源聯繫在一起。這個 ETag 後來被客戶端用來做有條件的 HTTP 請求,說明 "如果 ETag 與我的 ETag 不一樣,就給我這個資源",只有在 ETag 不匹配的情況下才會下載內容

生成 ETag 的方法在 HTTP 文檔中沒有指定,通常使用一些抗碰撞的哈希函數來給資源的每個版本分配 ETag。可以有兩種類型的 etag,即強和弱的 etag。

ETag: "j82j8232ha7sdh0q2882" - Strong Etag
ETag: W/"j82j8232ha7sdh0q2882" - Weak Etag (prefixed with `W/`)

強驗證 ETag 意味著兩個資源是完全相同的,它們之間根本沒有區別。而一個弱的 ETag 意味著兩個資源雖然嚴格意義上不一樣,但可以被認為是相同的。例如,弱的 ETag 可能對動態內容很有用。

現在我們知道什麼是 Etag 了,但瀏覽器是如何提出這個請求的呢? 透過向伺服器提出請求,同時在If-None-Match頭中發送可用的 Etag。

考慮一下這樣的情況:你打開了一個網頁,其中加載了一個標誌圖片,快取期為 60 秒,ETag 為abc123xyz。大約 30 分鐘後,你重新加載該網頁,瀏覽器會注意到 60 秒內新鮮的標誌現在已經過時了;它將觸發一個請求給伺服器,在 if-none-match 頭中發送過時的標誌圖像的 ETag

If-None-Match: "abc123xyz"

然後,伺服器將比較這個 ETag 和資源的當前版本的 ETag。如果兩個 ETag 都匹配,伺服器將發回 304 未修改的響應,這將告訴客戶,它所擁有的副本仍然是好的,它將被視為新的 60 秒。如果兩個標誌都不匹配,即標誌很可能已經改變,客戶端將被發送新的標誌,它將用來替換它所擁有的陳舊的標誌。

Last-Modified

伺服器可能包括Last-Modified標頭,表明一些內容最後被修改的日期和時間。

Last-Modified: Wed, 15 Mar 2017 12:30:26 GMT

當內容過期時,客戶端將向伺服器發出一個條件性請求,其中包括它在名為If-Modified-Since的頭中的最後修改日期,以獲得更新的 Last-Modified 日期;如果它與客戶端的日期相匹配,內容的Last-Modified日期將被更新,以便在另外的 n 秒內被視為新鮮。如果收到的Last-Modified日期與客戶擁有的日期不一致,則從伺服器重新加載內容,並替換為客戶擁有的內容。

If-Modified-Since: Wed, 15 Mar 2017 12:30:26 GMT

你現在可能會問,如果快取的內容既有Last-Modified,又有ETag,怎麼辦?那麼,在這種情況下,兩者都要使用,也就是說,當且僅當 ETag 與新檢索的內容相匹配,並且 Last-Modified 日期也相匹配時,將不會有資源重新下載。如果 ETag 不匹配或者 Last-Modified 日期大於伺服器上的日期,內容就必須重新下載。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。