HTTP快取筆記整理
前言
快取是效能優化的總要手段,合理使用快取,不僅能夠節省伺服器資源,更能為使用者提供好的瀏覽體驗
Pragma
Pragma: no-cache
是 HTTP 1.0 的產物,它要求快取伺服器在返回快取的版本之前將請求提交到源頭伺服器進行驗證。在效果上和HTTP 1.1 中的Cache-Control: no-cache
一樣。
快取伺服器是代理伺服器的一種,用於快取靜態資源。通常資源在儲存到資料庫中時,我們會同時儲存資源的建立時間和更新時間,然後設定響應頭的Last-Modified
欄位為資源的最新更新時間,當下一次請求到達時,服務端會先讀取請求頭中的If-Modified-Since
的值,判斷資源是否更新過,如果沒有更新就返回304,資料返回空;如果更新過,狀態碼返回200,並返回新的資料
Expires
Expires: <GMT>
也是HTTP 1.0 的產物,用來告訴瀏覽器資源快取過期時間,如果還沒過該時間點則不發請求。由於伺服器時間和客戶端的時間可能有偏差,所以這種方式設定的快取時間並不可靠
Cache-Control
Cache-Control 是 HTTP 1.1 中的欄位,取值如下:
public: 表示允許快取HTTP請求經過的任何地方都可以快取
private: 表示只允許發起請求的瀏覽器進行快取
no-cache:允許使用本地和代理伺服器快取,但要求在返回快取的版本之前將請求提交到源頭伺服器進行驗證
no-store: 不允許本地和代理伺服器快取,必須要到源伺服器請求最新資源(即使本地或代理伺服器有快取)
no-transform: 不允許快取伺服器對資源進行轉換(比如壓縮)
max-age=
s-maxage=max-age
和s-maxage
,瀏覽器會根據max-age進行快取,代理伺服器會根據s-maxage進行快取
must-revalidate:如果快取過期了,瀏覽器必須要到源伺服器傳送請求
proxy-revalidate:如果快取過期了,快取伺服器必須要到源伺服器傳送請求
// 瀏覽器和代理伺服器對資源快取一年,並且每次請求都到伺服器器去驗證 Cache-Control: max-age=31536000, no-cache
通常情況下服務端會設定1年的長快取,為了避免資源更新而瀏覽器仍然讀取快取的問題,前端可以把打包後的新資源加上hash值,然後上傳到靜態資源伺服器,由於檔案地址已經改變,瀏覽器就會去載入新的檔案,這是目前使用廣泛的快取解決方案
ETag
ETag 是HTTP 1.1 推出的快取驗證欄位,它相比於Last-Modified
這種基於時間的驗證方式要更加可靠。服務端在返回資源時先基於某種演算法計算出資源的唯一值(比如hash),然後設定到ETag裡,下次請求時瀏覽器會自動帶上If-None-Match: <ETag-value>
,伺服器通過判斷Etag值決定是否返回新的資源,
Nginx 快取
Nginx 快取類似於瀏覽器快取,只不過一個存在使用者本地,一個存在伺服器。開啟快取的方法很簡單,在配置檔案中新增下面兩行程式碼
# proxy_cache_path:快取資源的路徑;levels:開啟二級目錄;keys_zone:快取關係佔用記憶體大小(cache下可以有很多快取資料夾,資料夾和快取資源的對應關係需要儲存到記憶體中)
proxy_cache_path /var/cache levels=1:2 keys_zone=my_cache:10m
server {
proxy_cache my_cache;
}
代理快取優勢:只要第一個使用者傳送了請求,代理伺服器就可以進行資源快取,後面的所有請求都能從快取中讀取,即使使用者切換了瀏覽器效果也是一樣的,因為它是針對URL進行快取的。源伺服器設定的max-age
值對瀏覽器和代理伺服器都是有效的,也可以通過s-maxage
對代理伺服器單獨設定快取時間
vary
上面的快取都是基於URL,即只要請求的地址是一樣的,就允許瀏覽器或代理伺服器進行快取。但是實際開發中可能有這樣的需求,要求同一個URL根據不同的國家返回不同的資料,或者根據不同的終端(手機端和PC端)返回不同的資料,這時候就不能簡單的只存取一種快取了,Vary欄位就是解決同一個URL不同快取的問題的
Vary=<value>
比如我們在服務端設定了 Vary: X-Test-Cache
,然後客戶端傳送請求時,在請求頭中添加了X-Test-Cache: zh-CN
,此時快取伺服器會進行首次快取。然後下次請求是可能是一個外國朋友傳送的,它的請求頭是X-Test-Cache: en-US
,這時候不會從快取中讀取資料,而是向源伺服器傳送一個新的請求,快取伺服器再對這次結果進行快取。後面的請求如果是來自zh-CN
就讀取zh-CN
中的快取,如果來自en-US
就讀取en-US
的快取,這樣就解決了同一個URL不同快取的問題
GitHub: https://github.com/wmui