寫在前面
電面被問到這個問題样眠,當(dāng)時就懵了割笙,之后仔細(xì)看了下這個緩存策略权烧,HTTP博大精深啊眯亦,小弟不才望,多多指正般码。
HTTP定義了與服務(wù)器交互的方式妻率,其中最基本的有四種:GET,POST,PUT,DELETE可以說是對應(yīng)著查、改板祝、增宫静、刪。
1券时、GET /url/xxx 查看
2孤里、POST /url 創(chuàng)建
3、PUT /url/xxx 更新
4革为、DELETE /url/xxx 刪除
一個完整頁面顯示過程-HTTP工作流程
1.當(dāng)一個瀏覽器輸入URL向服務(wù)器發(fā)送一個Request實際是為了得到這個URL的html扭粱,之后在本地會收到一個Response.
2瀏覽器接收到Response分析得到html,發(fā)現(xiàn)其中有很多圖片還有文件震檩。
3.瀏覽器繼續(xù)發(fā)送Request從而獲取圖片琢蛤,CSS,JS文件抛虏。
4.獲取成功在瀏覽器將網(wǎng)頁顯示出來
GET和POST區(qū)別
1.參數(shù):GET參數(shù)是直接放到URL上面博其,通過'?'和'&'鏈接參數(shù)。POST是將參數(shù)放到了body體中進(jìn)行數(shù)據(jù)傳輸迂猴。這又證明了兩點:一慕淡、GET請求沒有body二、相對來說POST安全一些沸毁,只是針對用戶而言峰髓。但是兩者實際上都是不安全的,參數(shù)不加密的話隨便的抓包軟件都能輕松搞定息尺。
2.數(shù)據(jù)量:GET有大小限制携兵,傳統(tǒng)IE中URL的最大可用長度為2048字節(jié),其他瀏覽器對URL長度限制實現(xiàn)上有所不同搂誉。POST請求沒有限制徐紧。
3.GET使用Request.QueryString來取得變量的值。POST方式通過Request.Form來獲取變量的值炭懊。(這個我不是很理解并级,望小伙伴給講解)。
步入正題
HTTP緩存侮腹,明確的要知道GET請求可以被緩存嘲碧,POST不能被緩存,所以要想在客戶端做HTTP的緩存一定要注意使用GET請求凯旋!
頭域的概念:一圖勝千言下圖中的右邊欄加粗字體都是頭域:
Cache,Client,Entity,Transport等等
再看左欄的Result也就是狀態(tài)碼:可以看到我這是304:這代碼當(dāng)前頁面在本地的緩存沒有過期和服務(wù)器一致呀潭,可以使用钉迷!那這是怎么做到的呢?有下面兩種方式钠署。
If-Modified-Since/Last-Modified
If-Modified-Since這個是在Request里面的Cache中的信息用來表示本地緩存最后一次被修改的時間糠聪,他被發(fā)送到服務(wù)器并且和Response的Entity中Last-Modified作比較,如果兩者的日期一致谐鼎,那就說明在此期間頁面沒有任何改動瀏覽器可以使用本地緩存舰蟆。(所提到的頭域都可以在上面圖中找到,大家結(jié)合圖來看比較清晰)
If-None-Match/Etag
If-None-Match是在Request中請求頭的第一行狸棍,他存儲一個字符串(資源在服務(wù)器的唯一確定標(biāo)志)身害。Etag是Response中Entity中的一個字符串。兩個也是做比較草戈,相同說明可以使用緩存塌鸯。
http協(xié)商緩存中:Etag/lastModified完整過程(可以配合上面的HTTP流程理解):
1.客戶端請求一個頁面(A)。
2.服務(wù)器返回頁面A唐片,并在給A加上一個Last-Modified/ETag丙猬。
3.客戶端展現(xiàn)該頁面,并將頁面連同Last-Modified/ETag一起緩存费韭。
4.客戶再次請求頁面A茧球,并將上次請求時服務(wù)器返回的Last-Modified/ETag一起傳遞給服務(wù)器。
5.服務(wù)器檢查該Last-Modified或ETag星持,并判斷出該頁面自上次客戶端請求之后還未被修改抢埋,直接返回響應(yīng)304和一個空的響應(yīng)體。
那么問題來了為什么要使用兩種緩緩存方式呢督暂?而且從我的截圖中可以看到僅有第二種Etag方式
原因如下:
1.如果一些資源定期生成揪垄,這種情況下內(nèi)容沒有變化但是服務(wù)器的 Last-Modified改變了,導(dǎo)致文件使用不了緩存逻翁。
2.Last-Modified的日期只能精確到秒從上面截圖可以看到福侈,如果在1s內(nèi)做了修改,那么就會出現(xiàn)誤判
3.由于If-Modified-Since/Last-Modified這種方式使用時間判斷一定要保證服務(wù)器和本地的時間的一致卢未。
Etag是資源在服務(wù)器的唯一標(biāo)識符,能夠更加準(zhǔn)確的控制緩存堰汉。Last-Modified 與 ETag 是可以一起使用的辽社,
但是服務(wù)器會優(yōu)先驗證 ETag,在一致之后才會判斷Last-Modified翘鸭,判斷是否返回304.
修正:當(dāng)兩者同時存在的時候,通過以下表達(dá)式來進(jìn)行緩存策略的判斷.感謝@我在睡覺
if ETagFromServer != ETagOnClient || LastModifiedFromServer != LastModifiedOnClient
GetFromServer
else
GetFromCache
參考: StackOverflow-the ETag or Last-Modified HTTP header?
使用Ctrl+F5 強制刷新頁面滴铅,可以忽略以上講的兩種緩存策略
操作 | Cache-Control | Last-Modified/Etag |
---|---|---|
前進(jìn)后退 | 有效 | 有效 |
刷新-F5 | 無效 | 有效 |
強制刷新 | 無效 | 無效 |
緩存過期時間
Expires:到期時間。作用: 瀏覽器會在指定過期時間內(nèi)使用本地緩存
你可以設(shè)置這個時間為Sun, 17-Jan-2038 19:14:07 GMT就乓,因為這個時間是32位unix支持的最大的時間值汉匙,就可以做到緩存的東西一直有效拱烁。
如果將這個值設(shè)置成-1那么緩存將會立即失效。
如果沒有設(shè)置Expires
對于firefox失效時間=0.1*(Time-Last-Modified )噩翠,上一次時間的0.1的時間后失效戏自。這樣設(shè)計很有道理月九沒修改越久的保存效果。如果10沒有修改1天后就會失效伤锚。
總之擅笔,不同的瀏覽器會有不同的清空緩存方法,大家有興趣可以看一下屯援。
Cache-Control
通過指定頭域Cache-Control猛们,就能實現(xiàn)控制緩存的工作機制。
指令的參數(shù)是可選的狞洋,多個指令之前可以通過‘弯淘,’來實現(xiàn)。請求響應(yīng)時使用吉懊。
緩存請求指令
指令 | 參數(shù) | 說明 |
---|---|---|
no-cache | 無 | 強制向源服務(wù)器在次驗證 |
no-store | 無 | 不緩存請求或響應(yīng)任何內(nèi)容 |
only-if-cached | 無 | 從緩沖獲取資源 |
cache-extension | - | 新指令標(biāo)記 |
緩存響應(yīng)指令
指令 | 參數(shù) | 說明 |
---|---|---|
public | 無 | 可以向任意方提供相應(yīng)的緩存 |
private | 可省略 | 向指定用戶返回響應(yīng) |
no-cache | 可省略 | 緩存前必須確認(rèn)其有效性 |
cache-extension | - | 新指令標(biāo)記 |
在緩存請求中使用no-cache指令的目的是為了防止從緩存中返回過期的資源庐橙。
客戶端發(fā)送的請求中如果包含no-cache指令,則表示客戶端將不會接收緩存過的響應(yīng)惕它。于是怕午,中間的緩存服務(wù)器必須把客戶端請求轉(zhuǎn)發(fā)給源服務(wù)器。
如果服務(wù)器返回的響應(yīng)中包含no-cache指令淹魄,那么緩存服務(wù)器不能對資源進(jìn)行緩存郁惜。源服務(wù)器以后也將不再對緩存服務(wù)器請求中提出的資源進(jìn)行有效確認(rèn),禁止其對響應(yīng)資源進(jìn)行緩存操作甲锡。
一般的參數(shù)會采用no-cache這個指令表示避免使用過期緩存兆蕉。而no-store表示真正完全不使用緩存
only-if-cached只從緩存服務(wù)器本地中換取緩存。只要緩存服務(wù)器無法加載響應(yīng)缤沦,就會返回錯誤狀態(tài)碼504Gateway Timeout虎韵。
使用
在iOS上優(yōu)雅的使用etag緩存
TeamWe github