HTTP協議探究(一)
阿新 • • 發佈:2018-11-23
cati disk 私有 bubuko 改變 form sha 決定 本地
一 復習與目標
1 復習
- 序章主要用WrieShark抓包HTTP報文
- 復習了TCP協議
- 講述了TCP協議與HTTP之間的關系
- HTTP1.1更新原因:HTTP1.0一次TCP連接只能發送一次HTTP報文等
- HTTP2.0更新原因:HTTP的報頭太大、多路復用問題等(HTTP2.0未來研究)
2 目標
- 由於大家都有一定的基礎(包括我),所以並不會照著書本一節一節地進行,所以這一節重點講一下緩存相關的問題。
- 緩存的好處
- 緩存相關的狀態碼
- 緩存相關的首部
- 緩存的處理步驟
二 為什麽要有緩存?
- 減少冗余的數據傳輸
- 緩解網絡瓶頸
- 降低對源服務器的要求
- 降低距離時延
註:其實所有的好處都是不去重復獲取相同文件帶來的。
三 緩存存放在哪裏?
- 代理服務器(如:Nginx)
- 瀏覽器(如:Chrome)
註:由於現在一般前後端分離開發,如:前端用Angular(Nginx),後端用Java(Tomcat),前端打包構建(代碼壓縮 編譯優化 代碼混淆等操作)成靜態文件存放在Nginx中。本文主要以Chrome與Nginx的交互做例子。
四 緩存相關狀態碼
- 200:請求成功
- 304:請求資源服務器,返回資源未改動
- 200:過期時間內,瀏覽器直接獲取硬盤內的緩存數據(from disk cache)
- 304:過期時間內,瀏覽器直接獲取內存內的緩存數據(from memory cache)
五 緩存相關的HTTP首部
1 驗證相關
(1)Etag示例
# 以Nginx生成的Etag值為例
# etag == last-modified的秒級Unix時間戳(16進制) - content-length(16進制)
# 響應首部
last-modified: Fri, 23 Nov 2018 03:47:36 GMT
content-length: 1408
etag: W/"5bf77858-580"
# 請求首部
if-none-match: W/"5bf77858-580"
if-modified-since: Fri, 23 Nov 2018 03:47:36 GMT
- Nginx收到請求後,比較Etag值是否修改,修改則返回新文件,狀態碼為200。
- 否則,返回狀態嗎304,告知瀏覽器從硬盤獲取即可。
(2)強弱驗證器
- 弱驗證器:服務器對文檔進行一些非實質性或不重要的修改時,不希望已緩存的副本都失效。Etag表達:"5bf77858-580"。
- 強驗證器:文檔進行任何修改都會使得緩存的副本失效。Etag表達:W/"5bf77858-580"。
2 Cache-Control
(1)響應請求角度
- 緩存請求指令
指令 | 參數 | 說明 |
---|---|---|
no-cache | 無 | 強制向源服務器再次驗證(返回200或者304) |
no-store | 無 | 不緩存請求或者響應的任何內容(返回200) |
max-age=[s] | 必須 | 響應的最大Age值 |
max-stale(=[s]) | 可省略 | 過期也照常接收 |
min-fresh=[s] | 必須 | 要求緩存服務器返回至少還未過指定時間的緩存資源 |
no-transform | 無 | 代理不可更改媒體類型 |
only-if-cached | 無 | 要求緩存服務器不重新加載響應,也不會再次確認資源有效性 |
- 緩存響應指令
指令 | 參數 | 說明 |
---|---|---|
public | 無 | 向任意方(代理或瀏覽器)提供響應的緩存 |
private | 可省略 | 僅向特定用戶(瀏覽器)返回響應 |
no-cache | 無 | 強制向源服務器再次驗證(返回200或者304) |
no-store | 無 | 不緩存請求或者響應的任何內容(返回200) |
no-transform | 無 | 代理不可更改媒體類型 |
must-revalidate | 無 | 代理可緩存但是必須再向源服務器進行確認(忽略請求的max-stale) |
proxy-revalidate | 無 | 所有緩存服務器在接收到客戶端帶有該指令的請求返回響應之前,必須再次驗證緩存的有效性 |
max-age=[s] | 可省略 | 響應的最大Age值(忽略請求的Expires) |
s-maxage = [ 秒] | 必需 | 公共緩存服務器響應的最大Age值 |
(2)功能角度
- 什麽是可以緩存的?響應(源服務器)決定
- public(共享緩存):響應消息可被任何緩存保存
- private(私有緩存):響應消息部分或者全部可被某個用戶(如:瀏覽器)保存,但不可被共享緩存保存。
- no-cache(不緩存):指定一個或多個field-name不可緩存,即每次都需要去驗證
- 什麽能被緩存保存?響應決定
- no-store(不保存):防止敏感信息泄露,整個響應消息都不能保存。
- 對基本過期機制改進?響應或者請求決定
- Expires:指定過期時間。
- s-maxage(針對代理服務器):對共享(緩存來說,s-maxage指定的值將會覆蓋max-age緩存控制指令或Expires頭域
- max-age(針對用戶終端):優先級高於Expires,max-age未到時,不會去源服務器請求,而是從本地硬盤或內存中獲取。
- min-fresh(保鮮時間):客戶端想要響應至少在保鮮時間(min-fresh)內。
- max-stale(過期時間):客戶端想要響應在保鮮時間內或過期不超過max-stale;若max-stale沒有賦值,則客戶端願接受任意年齡的陳舊響應。
- 緩存重驗證和加載控制?用戶代理(響應或者請求)決定
- max-age=0:強迫重驗證它所擁有的緩存項。
- only-if-cache:糟糕的網絡連接下,客戶端希望緩存只返回緩存當前保存的響應,並且不需要通過源服務器對其緩存項進行重新加載或重驗證。
- must-revalidate(針對代理服務器):如果基於源服務器的Expire或max-age值,已緩存的響應超過max-age時間,緩存必須每次重驗證。
- proxy-revalidate(針對用戶終端):類似於must-revalidate,但不適用於代理緩存。
(3)組合使用註意
- Cache-Control:max-age,s-maxage;時,那麽代理使用s-maxage進行緩存,瀏覽器使用max-age進行緩存。
- Cache-Control:no-cache,max-age=60;時,max-age失效。
- Cache-Control:no-cache,no-store;時,no-cache失效。
- revalidate能與max-age能夠配合使用,即max-age沒過期,使用本地;過期則去重新獲取。
- 單獨使用revalidate時,瀏覽器或代理會有默認的max-age,不同的瀏覽器該值不一樣(所以禁止這樣使用)。
- 請一定要指定private public來指定允許緩存的代理或瀏覽器
(4)示例
- 服務器:Nginx
- 客戶端:Chrome
# demo1
location / {
add_header Cache-Control max-age=30;
root /home/nginx/html;
index index.html;
}
# demo2
location / {
add_header Cache-Control private,max-age=30,proxy-revalidate;
root /home/nginx/html;
index index.html;
}
- 執行結果是一樣的,max-age時間內,從本地獲取,超出則訪問服務器。
- 但是我強烈建議使用第二種,因為Chrome中兩個的效果是相同的,鬼知道其他的瀏覽器會是怎樣的體現。
六 廢棄和更新緩存的響應
- HTML 被標記為“no-cache”,這意味著瀏覽器在每次請求時都始終會重新驗證文檔,並在內容變化時獲取最新版本。此外,在 HTML 標記內,您在 CSS 和 JavaScript 資產的網址中嵌入指紋:如果這些文件的內容發生變化,網頁的 HTML 也會隨之改變,並會下載 HTML 響應的新副本。
- 允許瀏覽器和中間緩存(例如 CDN)緩存 CSS,並將 CSS 設置為 1 年後到期。請註意,您可以放心地使用 1 年的“遠期過期”,因為您在文件名中嵌入了文件的指紋:CSS 更新時網址也會隨之變化。
- JavaScript 同樣設置為 1 年後到期,但標記為 private,這或許是因為它包含的某些用戶私人數據是 CDN 不應緩存的。
- 圖像緩存時不包含版本或唯一指紋,並設置為 1 天後到期。
註:一般打包工具都具備給文件嵌入指紋,整個不需要擔心。
如:Angualr項目打包生成項目結構
index.html
assets
img
logo.png
...
1.4f4fe517e78bb7b8a11d.js # 組件混淆文件
styles.2c73b882414fbdd03a9f.css
....
七 緩存檢查清單
- 使用一致的網址:如果您在不同的網址上提供相同的內容,將會多次獲取和存儲這些內容。
- 確保服務器提供驗證令牌 (ETag):有了驗證令牌,當服務器上的資源未發生變化時,就不需要傳送相同的字節。(Nginx自帶Etag計算)
- 確定中間緩存可以緩存哪些資源:對所有用戶的響應完全相同的資源非常適合由 CDN 以及其他中間緩存進行緩存。(Nginx進行定制)
- 為每個資源確定最佳緩存周期:不同的資源可能有不同的更新要求。為每個資源審核並確定合適的 max-age。(Nginx進行定制)
- 確定最適合您的網站的緩存層次結構:您可以通過為 HTML 文檔組合使用包含內容指紋的資源網址和短時間或 no-cache 周期,來控制客戶端獲取更新的速度。(Angular打包自動支持)
- 最大限度減少攪動:某些資源的更新比其他資源頻繁。如果資源的特定部分會經常更新,可以考慮將其代碼作為單獨的文件提供。這樣一來,每次獲取更新時,其余內容可以從緩存獲取,從而最大限度減少下載的內容大小。
參考:
- https://www.cnblogs.com/chyingp/p/no-cache-vs-must-revalidate.html
- https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn
- https://www.web-tinker.com/article/21217.html
- https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
- 《HTTP權威指南》第7章
- 《圖解HTTP》第6章
HTTP協議探究(一)