近日,發現我打包的js
代碼上傳到服務器後,並無更新。想到用ng
作了代理,多是ng
緩存的問題,就查資料學習了一下http
(1.1)緩存的東西。css
req
爲請求頭,res
響應頭,C
客戶端,S
服務端)// response Headers
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 04 Dec 2019 09:11:07 GMT
Content-Type: text/css
Vary: Accept-Encoding
Last-Modified: Wed, 04 Dec 2019 09:03:18 GMT
ETag: W/"5de77656-2340"
Expires: Wed, 04 Dec 2019 21:11:06 GMT
Cache-Control: max-age=43200
Content-Encoding: gzip
複製代碼
res
中爲資源過時時間res
中爲資源最近修改時間res
中資源的惟一標識符(hash算法生成)req
中的資源最近修改時間req
中的資源標識res
,req
中表示緩存策略req
中經常使用指令字段名稱 | 說明 |
---|---|
max-age= | 設置緩存存儲的最大週期,超過這個時間緩存被認爲過時(單位秒)。與Expires 相反,時間是相對於請求的時間 |
max-stale[=] | C 可接收一個已通過期的資源。設置一個可選的秒數,不接受超過給定時間的資源 |
min-fresh= | C 但願獲取一個能在指定的秒數內保持其最新狀態的res |
no-cache | 在發佈緩存副本以前,強制要求緩存把請求提交給原始服務器進行驗證 |
no-store | 不緩存有關客戶端請求或服務器響應的任何內容 |
res
中經常使用指令(req中重複的不列舉,詳見MDN)字段名稱 | 說明 |
---|---|
public | 代表響應能夠被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存,即便是一般不可緩存的內容 |
private | 代表響應只能被單個用戶緩存,不能做爲共享緩存(即代理服務器不能緩存它)。私有緩存能夠緩存響應內容 |
must-revalidate | 一旦資源過時(好比已經超過max-age ),在成功向原始服務器驗證以前,緩存不能用該資源響應後續請求 |
proxy-revalidate | 與must-revalidate 做用相同,但它僅適用於共享緩存(例如代理),並被私有緩存忽略 |
s-maxage= | 覆蓋max-age 或者Expires 頭,可是僅適用於共享緩存(好比各個代理),私有緩存會忽略它 |
其中Last-Modified
與If-Modified-Since
,ETag
與If-None-Match
是在每次的res,req中配對使用的。html
過程vue
C
端請求app.js ----> S
端。S
端響應app.js 與Expires ----> C
端。(C
端緩存app.js直到Expires)優點nginx
相比於最原始的不帶緩存的請求和相應,優點很明顯,會直接從緩存中取,減小請求響應次數git
缺陷github
若是app.js在Expires 內發生了改變,C
端呈現的資源不是最新的。web
過程面試
C
端請求app.js ----> S
端S
端響應app.js 與Expires, Last-Modified ----> C
端。(C
端緩存app.js直到Expires,上次修改時間是 Last-Modified)C
端請求S
端,帶上If-Modified-Since(等於上一次相應的Last-Modified)S
端用req
中的If-Modified-Since和res
中的 Last-Modified比較。
C
端:你能夠繼續用本地緩存(304)優點算法
相比與只使用Expires,if app.js發生變化,能夠更新緩存,C
端呈現內容爲最新,else 不會有新的res
拉一次資源,直接讀緩存vue-cli
缺陷
Last-Modified精確到秒,實際中有不少一秒內會完成不少req
和res
,問題呼之欲出
C
端仍是會從緩存中讀,呈現內容不是最新vue-cli
開發下,由於某種緣由,代碼實際沒有修改,但CI/CD重複構建打包了文件,app.js變爲了app01.js(build.js生成的不一樣版本hash名稱),但代碼只是名稱變化,內容並不變化,卻從新拉了一次資源過程
C
端請求app.js ----> S
端S
端響應app.js 與Expires, Last-Modified ,ETag----> C
端。(C
端緩存app.js直到Expires,上次修改時間是 Last-Modified,文件標識是ETag)C
端請求S
端,帶上If-Modified-Since(等於上一次相應的Last-Modified)和If-None-Match(等於上一次相應的Etag)
S
端用req
中的If-None-Match和res
中的 Etag比較,忽略掉If-Modified-Since和Last-Modified的比較。(若是Etag變化,Last-Modified必定變化,充分條件)C
端:你能夠繼續用本地緩存(304)優點
相較於上一種,使得資源變動的驗證更加嚴格。
缺陷
讓咱們設想這種狀況,咱們頻繁的修改app.js,打包構建,處於某種緣由,咱們並不想C
端呈現最新的app.js,而是一段時間後再讀取最新的,顯然還達不到咱們的要求
過程
C
端請求app.js ----> S
端S
端響應app.js 與Expires, Last-Modified ,ETag, Cache-Control:max-age=43200 ----> C
端。(C
端發現帶有 Cache-Control:max-age=43200,忽略Expires*,記住Last-Modified ,ETag)req
發生的時間+ 12h(43200s)),會直接從緩存中取(200)。
C
端請求S
端,帶上If-Modified-Since(等於上一次相應的Last-Modified)和If-None-Match(等於上一次相應的Etag)
S
端用req
中的If-None-Match和res
中的 Etag比較,忽略掉If-Modified-Since和Last-Modified的比較。(若是Etag變化,Last-Modified必定變化,充分條件)C
端:你能夠繼續用本地緩存(304)優點
達到了咱們上個方案達不到的效果
缺陷?
C
端沒法主動知道S
端上咱們請求的資源變化,只能被動的從res
中得知,這算缺陷嗎?
如何設置不緩存?
ng配置以下:
// 還有多種設置方法,舉例一種
// 重啓ng不必定當即生效
location / {
access_log /data/nginx/log/xxx.log api;
root /home/www/html;
if ($request_filename ~ .*\.(htm|html)$)
{
add_header Cache-Control no-cache;
}
}
複製代碼
打包html
設置meta
標籤以下
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
複製代碼
meta是用來在HTML文檔中模擬HTTP協議的響應頭報文。meta 標籤用於網頁的與中,meta 標籤的用處不少。meta 的屬性有兩種:name和http-equiv。name屬性主要用於描述網頁,對應於content(網頁內容),以便於搜索引擎機器人查找、分類(目前幾乎全部的搜索引擎都使用網上機器人自動查找meta值來給網頁分類)。這其中最重要的是description(站點在搜索引擎上的描述)和keywords(分類關鍵詞),因此應該給每頁加一個meta值。
如何清理緩存?
Nginx企業版提供了purger功能,對於社區版Nginx能夠考慮使用ngx_cache_purge
(該方法最好限制其訪問權限,如只容許內網能夠訪問或者須要密碼才能訪問)github.com/FRiCKLE/ngx…
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge cache$1$is_args$args;
}
複製代碼
PS: 相似寶塔面板這種Ng都自動安裝了ngx_cache_purge
模塊,如何設置詳見下方參考。
找到緩存文件夾,直接kill。
若是發生緩存錯誤,檢查的步驟?
Network
,勾選js,F5
刷新後找到對應的app.xxx.js,比較。若是你發現名稱不同,並且res
頭部 Last-Modified也不對,那麼大機率你傳錯文件夾了。Server
只是http
(1.1)的部分常見場景,目前到這裏已經足夠,咱得一步一步來,切勿囫圇吞棗~
思考有限,不免出現疏漏,歡迎諸位指出,集思廣益。
歡迎關注個人公衆號《web工程師的自我修養》,一塊兒交流學習共勉~