一 複習與目標
1 複習
- 序章主要用WrieShark抓包HTTP報文
- 複習了TCP協議
- 講述了TCP協議與HTTP之間的關係
- HTTP1.1更新緣由:HTTP1.0一次TCP鏈接只能發送一次HTTP報文等
- HTTP2.0更新緣由:HTTP的報頭太大、多路複用問題等(HTTP2.0將來研究)
2 目標
- 因爲你們都有必定的基礎(包括我),因此並不會照着書本一節一節地進行,因此這一節重點講一下緩存相關的問題。
- 緩存的好處
- 緩存相關的狀態碼
- 緩存相關的首部
- 緩存的處理步驟
二 爲何要有緩存?
- 減小冗餘的數據傳輸
- 緩解網絡瓶頸
- 下降對源服務器的要求
- 下降距離時延
注:其實全部的好處都是不去重複獲取相同文件帶來的。css
三 緩存存放在哪裏?
- 代理服務器(如:Nginx)
- 瀏覽器(如:Chrome)
注:因爲如今通常先後端分離開發,如:前端用Angular(Nginx),後端用Java(Tomcat),前端打包構建(代碼壓縮 編譯優化 代碼混淆等操做)成靜態文件存放在Nginx中。本文主要以Chrome與Nginx的交互作例子。html
四 緩存相關狀態碼
- 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)示例
# 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中兩個的效果是相同的,鬼知道其餘的瀏覽器會是怎樣的體現。
六 瀏覽器的緩存處理流程
(1)處理流程
- HTTP響應判斷是否可緩存?
- 確保Cache-Control值沒有no-store或no-cache修飾
- 確保Cache-Control值有private或public修飾,通常默認值就是可緩存(響應建議顯式加上)
- HTTP響應緩存多久?
- Cache-Control中的max-age(單位:秒)
- HTTP請求過程:
- 第一步:判斷本地是否有緩存(max-age未過時),未過時直接本地獲取
- 第二步:過時則首部帶上驗證信息(if-none-match:"響應的etag值" if-modified-since:"響應的last-modified值")
- 第三步:服務器驗證本地文件與HTTP請求的Etag值與最後修改時間,若是相同直接返回304,讓瀏覽器繼續使用本地緩存,不然返回200,即返回新的文件和Etag值。(對應第七節)
(2)廢棄和更新緩存的響應
![](http://static.javashuo.com/static/loading.gif)
- HTML 被標記爲「no-cache」,這意味着瀏覽器在每次請求時都始終會從新驗證文檔,並在內容變化時獲取最新版本。此外,在 HTML 標記內,您在 CSS 和 JavaScript 資產的網址中嵌入指紋:若是這些文件的內容發生變化,網頁的 HTML 也會隨之改變,並會下載 HTML 響應的新副本。
- 容許瀏覽器和中間緩存(例如 CDN)緩存 CSS,並將 CSS 設置爲 1 年後到期。請注意,您能夠放心地使用 1 年的「遠期過時」,由於您在文件名中嵌入了文件的指紋:CSS 更新時網址也會隨之變化。
- JavaScript 一樣設置爲 1 年後到期,但標記爲 private,這或許是由於它包含的某些用戶私人數據是 CDN 不該緩存的。
- 圖像緩存時不包含版本或惟一指紋,並設置爲1天后到期。
注:通常打包工具都具有給文件嵌入指紋,整個不須要擔憂。前端
如:Angualr項目打包生成項目結構nginx
index.html
assets
img
logo.png
...
1.4f4fe517e78bb7b8a11d.js # 組件混淆文件
styles.2c73b882414fbdd03a9f.css
....
(3)緩存使用清單
- 使用一致的網址:若是您在不一樣的網址上提供相同的內容,將會屢次獲取和存儲這些內容。
- 確保服務器提供驗證令牌 (ETag):有了驗證令牌,當服務器上的資源未發生變化時,就不須要傳送相同的字節。(Nginx自帶Etag計算)
- 肯定中間緩存能夠緩存哪些資源:對全部用戶的響應徹底相同的資源很是適合由 CDN 以及其餘中間緩存進行緩存。(Nginx進行定製)
- 爲每一個資源肯定最佳緩存週期:不一樣的資源可能有不一樣的更新要求。爲每一個資源審覈並肯定合適的 max-age。(Nginx進行定製)
- 肯定最適合您的網站的緩存層次結構:您能夠經過爲 HTML 文檔組合使用包含內容指紋的資源網址和短期或 no-cache 週期,來控制客戶端獲取更新的速度。(Angular打包自動支持)
- 最大限度減小攪動:某些資源的更新比其餘資源頻繁。若是資源的特定部分會常常更新,能夠考慮將其代碼做爲單獨的文件提供。這樣一來,每次獲取更新時,其他內容能夠從緩存獲取,從而最大限度減小下載的內容大小。
七 中間代理的緩存處理流程
- 接收:讀取抵達的請求報文
- 解析:報文解析,提取URL和首部
- 查詢:查詢本地副本是否可用,若是沒有,則從新獲取一份
- 新鮮度檢查:檢查緩存副本是否新鮮,不新鮮則詢問服務器是否有更新
- 建立響應:用新的首部和以緩存的主體構建一條響應報文
- 發送:經過網絡把響應發回給客戶端(能夠是中間緩存服務器也可使瀏覽器)
- 日誌(可選):建立一條日誌文件來描述這個事務
參考:web