《緩存知識體系之-瀏覽器緩存》要點:
本文介紹了緩存知識體系之-瀏覽器緩存,希望對您有用。如果有疑問,可以聯系我們。
現在我們把注意力關注到瀏覽器本身,那么我們要知道的是瀏覽器本質上是一個HTTP代理,它幫助用戶發送HTTP請求給Web服務器,然后Web服務器響應請求,返回數據給瀏覽器,瀏覽器進行本地渲染展示給用戶.那么瀏覽器能不能把Web服務器返回的網頁或者圖片、css、js等這些資源保存下來,下次我們再訪問相同的資源的時候直接讀取緩存呢?
現在我們有兩個伙伴,瀏覽器和Web服務器,Web服務器希望能緩存一些數據到瀏覽器上,但是瀏覽器并不知道哪些數據要緩存,哪些數據不緩存,那么他們兩個就需要對話.由于我們瀏覽器和Web服務器本身的通信協議就是HTTP,那么是不是就可以通過HTTP來進行對話呢,我們把這個瀏覽器和Web服務器之間有關緩存的對話稱之為“緩存協商”,雖然有點像小學課文的名詞解釋,但是我們現在知道了一個專業的名詞-“緩存協商”.
瀏覽器和Web服務器緩存協商的第一個方法是Last-Modified,也就是最后修改時間.我們知道我們的網頁存放在Linux服務器上會有三個時間,我們可以使用stat來獲取.
那么Web服務器默認情況下可以通過stat()系統調用獲取到靜態文件index.html在硬盤上的最后修改時間,而且在響應HTTP請求的時候回會為靜態文件在HTTP響應頭部自動生成最后修改時間.比如下面我們使用Firefox的Firebug插件來查看alidns.com(阿里提供的公共DNS).
在上面的這個圖中,我們打開http://alidns.com,瀏覽器發送的第一個請求GET alidns.com,我們可以看到Web服務器返回200的狀態碼,同時在響應頭中,告訴了瀏覽器,它這個文件的最后修改時間.好的,我們先不要著急,先來研究下這些緩存存放在哪里.對于firefox瀏覽器來說,是使用二進制格式保存的,不過我們可以使用about:cache來查看.直接在瀏覽器的地址欄輸入即可.
我們可以看到firefox默認有兩種緩存保存的地方,一個是內存中,一個是保存在磁盤中,還有一個是應用本身的緩存.(如果你的瀏覽器已經打開很久,可能需要清空緩存后,才能更快的找到剛才的alidns.com的緩存)我們現在再次刷新下頁面,你可以按F5、回車鍵或者firefox上面的重載頁面的圖標.
我們再次使用firefox的firebug看看發生了什么,首先之前的返回的狀態碼由200變成了304.我們先看下面的請求頭的信息.再第二次訪問alidns.com的時候瀏覽器在請求頭部增加了If-Modified-Since????? Fri, 11Jul 2014 03:25:04 GMT的內容,意思是詢問瀏覽器:瀏覽器大哥,請問下這個文件在我這個時間后有沒有更改過,如果沒有更改過,我就使用我本地緩存給用戶呈現頁面了哦.再看最上面,Web服務器非常果斷的回復304,也就是這個文件在你之前保存的最后修改時間后,沒有更改過,你可以使用本地緩存.
好的,我們可以看到瀏覽器和Web服務器協商的很愉快,對于訪問我們站點的用戶來說,如果之前訪問過我們的網站,那么第二次打開相同的靜態頁面,就不會產生實際的文件傳輸.為我們節約了服務器的帶寬,同時由于瀏覽器直接使用本地緩存呈現給用戶,所以用戶打開我們站點的速度也是非常的快.
我們現在要介紹另外一個緩存協商的方法,因為在某些場景下Last-Modified可能工作的并不愉快,比如有一種情況,我們的Web服務器上面的文件最后修改時間會頻繁的變動,但是文件內容卻沒有修改.那么對于Last-Modified的緩存協商,每次都會重新獲取文件,而不會使用緩存.
還有一種生產中比較常見的場景,比如我們在集群環境中,相同的網頁可能被保存在不同的服務器上,在負載均衡的時候用戶的請求會被分配到這些不同的服務器中,但是我們很難保證相同的文件在所有服務器上的最后修改時間都是一致的.那么這樣用戶請求被分發到時間不對的服務器上時,可能會導致瀏覽器會重新獲取網頁內容.
Etag這個時候站出來勇敢的承擔一切,HTTP1.1協議中并沒有規定Etag的具體格式和生產的方法,總之Web服務器可以給每一個靜態文件都生產一個標簽,或者叫指紋,總之是一個唯一標識符(比如給文件做一個md5),當文件內容改變的時候就修改這個標簽,這樣瀏覽器和Web服務器之間就通過詢問網頁的Etag是否改變來進行緩存協商.
這里我不準備再次截圖,讀者可以自己使用firebug觀察下etag的工作方式,我要強調一下就是同時存在Etag和Last-Modified的時候,Etag的優先級要高.
我們先回過頭在看之前的兩種緩存協商辦法,瀏覽器給Web服務器發送HTTP請求來詢問是否可以使用緩存.如果Web服務器告訴瀏覽器使用緩存,那么瀏覽器就直接使用緩存呈現給用戶,你是否發現,這個詢問的HTTP請求是不是也占用了Web服務器的資源,即便不產生任何的數據傳輸,用戶還是需要等待這個請求發送到響應完畢.那么能不能不發送HTTP請求呢?比如第一次瀏覽器請求完畢后,Web服務器告訴瀏覽器這個網頁保存1小時,你1個小時之內不要再過來煩我哦.
和Last-Modified、Etab一樣我們常用的Web服務器Apache、Nginx都支持過期時間(Expires)的設置,當瀏覽器第一次請求資源的時候,Web服務器設置一個過期時間,那么在這段時間內,瀏覽器會直接使用本地緩存,而不發送任何的緩存協商.請看下面這個Nginx的配置實例:
這里將所有后綴為gif、jpg、jpeg、png、bmp、swf這些資源設置了30天的過期時間,而將js和css設置了1個小時的過期時間.你可以繼續使用firebug來觀察使用expires的情況.
昨天的公眾號講解的瀏覽器緩存的上篇,那么開始之前你可以需要了解的是在Web架構中還都有哪些緩存.剛好我準備了一個相對完整的《緩存知識體系》:https://www.unixhot.com/page/cache
三種瀏覽器協商的辦法讓瀏覽器和我們Web服務器愉快的玩耍,我們把用戶的瀏覽器當做我們派發到千家萬戶的緩存管理員,他們幫我們Web站點存放和管理緩存,并按照協商的辦法給用戶呈現,突然有一天有一個看似巧合而又普遍的時間打破了這一切.
如果服務器和用戶瀏覽器的時間不一致呢?我們Web服務器在工程師的管理下可以自動更新時間,保證時鐘同步,但是我們怎么保證用戶本地電腦的時間都是對的呢?我們并沒有辦法!那這樣就會帶來一個問題.比如上面我們將css和js的過期時間為一個小時,但是用戶的電腦比服務器時間晚了2個小時,那么用戶訪問Web站點每次瀏覽器都會認為立即過期,重新獲取數據而不會使用本地緩存,所以我們需要有機制來解決這個問題.
HTTP1.1中的Cache-Control出現了,用于彌補Expires的不足,通過max-age告訴瀏覽器緩存過期的相對時間,注意這個相對時間是相對于本地瀏覽器時間而設置的.
可以看到上圖中.max-age的為3600秒,也就是我們在Nginx設置的一個小時.這樣瀏覽器就會根據用戶本地時間來計算一個小時后,再讓緩過期.
還有一個小細節,不知道你之前是否注意到.瀏覽器和Web服務器之間協商的時間都是GMT時間,而我們中國實用的時間是GMT+8的時區,所以我們看到的時候比實際上少了8個小時,但是這絲毫不影響他們之間的協商.
Cache-control除了max-age還有以下一個不同的參數:
您真的會使用瀏覽器的刷新按鈕嗎?不同的刷新機制可以導致不同級別的緩存失效,讓我們來一起測試下.
瀏覽器會對所有沒有過期的內容直接使用本地緩存,這個時候Last-Modified、Etag、和Expires均不會受刷新的影響.
瀏覽器會在請求中附加必要的緩存協商,但不允許瀏覽器直接使用本地緩存.這個時候Last-Modified、ETag就要受影響,要發起緩存協商的動作,但是對Expires無效.
這種方式就是我們說的強制刷新,每次瀏覽器都發起一個全新的請求,不使用任何緩存.
不知道你是否發現問題,如果你修改了一個設置了Expires緩存1小時的文件,難道你要通知所有用戶使用Ctrl+F5強制刷新頁面嗎?這顯然不太可能,接下來我們要來談談瀏覽器緩存過期.
我們最終對于我們現在的所有靜態資源使用了expires的過期時間,徹底消滅了HTTP緩存協商中的HTTP請求,而且由于Cache-Control中適應本地的過期時間,我們應該明顯的看到網站流量的下降,但是如果有一天,我們上線了一個js,結果由于bug,我們必須馬上替換這個js文件.你們團隊敏捷的修復這個bug并發布上線.
這個時候問題來了:然而你會發現已經訪問過的用戶,依然使用的本地緩存的舊js,造成網站故障.這并不能怪瀏覽器,是你的Web服務器告訴他3小時之內不要過來煩我,直接使用瀏覽器本地緩存:比如你再nginx設置的是
解決的思路就是最簡單的就是修改文件名,這樣瀏覽器對于新的js文件肯定是會重新獲取的,如果你的Web框架有這樣的支持,這是再好不過的了,那么還有一種方式就是給文件使用參數加上時間戳:
http://www.example.com/js/code.js?20160101
這樣瀏覽器再解析這個url的時候,就會認為這個是一個新的文件,會重新獲取并不會使用瀏覽器本地緩存.那么不同的語言、不同的Web框架都會有不同的實現方式,這里不在舉例.
小技巧:如何查看已發布的小干貨?
分享嘉賓
趙舜東
江湖人稱趙班長,曾在武警某部負責指揮自動化的架構和運維工作,2008年退役后一直從事互聯網運維工作.曾帶團隊負責國內某電商的運維工作,SaltStack中國用戶組發起人、《saltstack入門與實踐》作者,《運維知識體系》作者.
趁現在,關注我們
牛人并不可怕,可怕的是牛人比我們還努力!關注“運維社區(微信ID:cloud-oaas)”公眾號,每天利用空閑時間閱讀一篇技術原創干貨,滿滿的小幸福.
長按圖片,選擇“識別圖中二維碼”,關注我們.
原創聲明:本文章由趙班長原創,請必須全文轉載,包括本行.
轉載請注明本頁網址:
http://www.snjht.com/jiaocheng/4441.html