最近在項目中遇到了 IE浏覽器因緩存問題未能成功向後端發送 GET類型請求 的bug,然後順藤摸瓜順便看了看緩存的知識,覺得有必要總結跟大家分享一下。
在前端開發中,性能一直都是被大家所重視的一點,然而判斷一個網站的性能最直觀的就是看網頁打開的速度。其中提高網頁反應速度的一個方式就是使用緩存。一個優秀的緩存策略可以縮短網頁請求資源的距離,減少延遲,并且由于緩存文件可以重複利用,還可以減少帶寬,降低網絡負荷。
1. 介紹
web緩存是指一個web資源(如html頁面,圖片,js,數據等)存在于web服務器和客戶端(浏覽器)之間的副本。
緩存會根據進來的請求保存輸出内容的副本;當下一個請求來到的時候,如果是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,還是向源服務器再次發送請求。比較常見的就是浏覽器會緩存訪問過網站的網頁,當再次訪問這個URL地址的時候,如果網頁沒有更新,就不會再次下載網頁,而是直接使用本地緩存的網頁。隻有當網站明确标識資源已經更新,浏覽器才會再次下載網頁。至于浏覽器和網站服務器是如何标識網站頁面是否更新的機制,将在後面介紹。
1.1 web緩存的作用
1.web緩存的作用顯而易見減少網絡帶寬消耗:無論對于網站運營者或者用戶,帶寬都代表着金錢,過多的帶寬消耗,隻會便宜了網絡運營商。當Web緩存副本被使用時,隻會産生極小的網絡流量,可以有效的降低運營成本。
2.降低服務器壓力:給網絡資源設定有效期之後,用戶可以重複使用本地的緩存,減少對源服務器的請求,間接降低服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過期機制降低爬取的頻率,也能有效降低服務器的壓力。
1.2 web緩存的類型
web緩存大緻可以分為以下幾種類型 詳細内容:
1.數據庫數據緩存
2.服務器端緩存
3.浏覽器端緩存
4.web應用層緩存
浏覽器通過代理服務器向源服務器發起請求的原理如下圖:
浏覽器先向代理服務器發起web請求,再将請求轉發到源服務器。它屬于共享緩存,所以很多地方都可以使用其緩存資源,因此對于節省流量有很大作用。
浏覽器緩存是将文件保存在客戶端,在同一個會話過程中會檢查緩存的副本是否足夠新,在後退網頁時,訪問過的資源可以從浏覽器緩存中拿出使用。通過減少服務器處理請求的數量,用戶将獲得更快的體驗
下面着重關注一下浏覽器緩存。
2. web緩存的工作原理
所有的緩存都是基于一套規則來幫助他們決定什麼時候使用緩存中的副本提供服務(假設有副本可用的情況下,未被銷毀回收或者未被删除修改)。這些規則有的在協議中有定義(如HTTP協議1.0和1.1),有的則是由緩存的管理員設置(如DBA、浏覽器的用戶、代理服務器管理員或者應用開發者)。
2.1 浏覽器端的緩存規則
1.對于浏覽器端的緩存來講,這些規則是在HTTP協議頭和HTML頁面的 Meta标簽中定義的。他們分别從新鮮度和校驗值兩個維度來規定浏覽器是直接使用緩存中的副本,還是需要去源服務器獲取更新的版本。
1.新鮮度(過期機制):也就是緩存副本有效期。一個緩存副本必須滿足以下任一條件,浏覽器會認為它是有效的,足夠新的,而直接從緩存中獲取副本并渲染
2.校驗值(驗證機制):服務器返回資源的時候有時在控制頭信息帶上這個資源的實體标簽Etag(Entity Tag),它可以用來作為浏覽器再次請求過程的校驗标識。如過發現校驗标識不匹配,說明資源已經被修改或過期,浏覽器需求重新獲取資源内容。
2.2.2使用緩存有關的HTTP消息報頭
一個URI的完整HTTP協議交互過程是由HTTP請求和HTTP響應組成的。有關HTTP詳細内容可參考《Hypertext Transfer Protocol — HTTP/1.1》、《HTTP協議詳解》等。
在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有:
稍微解釋一下:
1. Cache-Control
1.max-age(單位為s)指定設置緩存最大的有效時間,定義的是時間長短。當浏覽器向服務器發送請求後,在max-age這段時間裡浏覽器就不會再向服務器發送請求了。我們來找個資源看下。比如QQ推廣上的css資源,max-age=3600,也就是說緩存有效期為3600秒(也就是1h)。于是在1天内都會使用這個版本的資源,即使服務器上的資源發生了變化,浏覽器也不會得到通知。max-age會覆蓋掉Expires,後面會有讨論
2.s-maxage(單位為s)同max-age,隻用于共享緩存(比如CDN緩存)。比如,當s-maxage=60時,在這60秒中,即使更新了CDN的内容,浏覽器也不會進行請求。也就是說max-age用于普通緩存,而s-maxage用于代理緩存。如果存在s-maxage,則會覆蓋掉max-age和Expires header。
3.public 指定響應會被緩存,并且在多用戶間共享。也就是下圖的意思。如果沒有指定public還是private,則默認為public。
4.private 響應隻作為私有的緩存(見下圖),不能在用戶間共享。如果要求HTTP認證,響應會自動設置為 private
5.no-cache 指定不緩存響應,表明資源不進行緩存,但是設置了 no-cache 之後并不代表浏覽器不緩存,而是在獲取緩存前要向服務器确認資源是否被更改。因此有的時候隻設置 no-cache 防止緩存還是不夠保險,還可以加上 private 指令,将過期時間設為過去的時間。
6.no-store 絕對禁止緩存,一看就知道如果用了這個命令當然就是不會進行緩存啦~每次請求資源都要從服務器重新獲取。
7.must-revalidate 指定如果頁面是過期的,則去服務器進行獲取。這個指令并不常用,就不做過多的讨論了。
cache-control的種類這麼多,然而怎麼使用它們呢,參看下圖:
2. Expires
緩存過期時間,用來指定資源到期的時間,是服務器端的具體的時間點。也就是說, Expires=max-age 請求時間 ,需要和Last-modified結合使用。但在上面我們提到過,cache-control的優先級更高。Expires是Web服務器響應消息頭字段,在響應http請求時告訴浏覽器在過期時間前浏覽器可以直接從浏覽器緩存取數據,而無需再次請求。
3. Last-modified & If-modified-since
服務器端文件的最後修改時間,需要和cache-control共同使用,是檢查服務器端資源是否更新的一種方式。當浏覽器再次進行請求時,會向服務器傳送If-Modified-Since報頭,詢問Last-Modified時間點之後資源是否被修改過。如果沒有修改,則返回碼為304,使用緩存;如果修改過,則再次去服務器請求資源,返回碼和首次請求相同為200,資源為服務器最新資源。
4. Etag & & If-None-Match
根據實體内容生成一段hash字符串,标識資源的狀态,由服務端産生。浏覽器會将這串字符串傳回服務器,驗證資源是否已經修改,如果沒有修改,過程如下:
2.2.3 緩存報頭種類與優先級
1. Cache-Control與Expires
Cache-Control與 Expires的作用一緻,都是指明當前資源的有效期,控制浏覽器是否直接從浏覽器緩存取數據還是重新發請求到服務器取數據。隻不過 Cache-Control的選擇更多,設置更細緻,如果同時設置的話,其優先級高于 Expires。
2. Last-Modified與ETag
你可能會覺得使用 Last-Modified 已經足以讓浏覽器知道本地的緩存副本是否足夠新,為什麼還需要 Etag(實體标識)呢?HTTP1.1中Etag的出現主要是為了解決幾個 Last-Modified 比較難解決的問題:
(1)Last-Modified 标注的最後修改隻能精确到秒級,如果某些文件在1秒鐘以内,被修改多次的話,它将不能準确标注文件的新鮮度
(2)如果某些文件會被定期生成,當有時内容并沒有任何變化,但 Last-Modified 卻改變了,導緻文件沒法使用緩存
(3)有可能存在服務器沒有準确獲取文件修改時間,或者與代理服務器時間不一緻等情形
Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一标識符,能夠更加準确的控制緩存。Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一緻的情況下,才會繼續比對Last-Modified,最後才決定是否返回304。Etag的服務器生成規則和強弱Etag的相關内容可以參考,《互動百科-Etag》和《HTTP Header definition》,這裡不再深入。
3. Last-Modified/ETag 與 Cache-Control/Expires
配置 Last-Modified/ETag的情況下,浏覽器再次訪問統一URI的資源,還是會發送請求到服務器詢問文件是否已經修改,如果沒有,服務器會隻發送一個304回給浏覽器,告訴浏覽器直接從自己本地的緩存取數據;如果修改過那就整個數據重新發給浏覽器;
Cache-Control/Expires則不同,如果檢測到本地的緩存還是有效的時間範圍内,浏覽器直接使用本地副本,不會發送任何請求。兩者一起使用時, Cache-Control/Expires的優先級要高,即當本地副本根據 Cache-Control/Expires發現還在有效期内時,則不會再次發送請求去服務器詢問修改時間 Last-Modified或實體标識 Etag了。
一般情況下,兩者會配合一起使用,因為即使服務器設置緩存時間, 當用戶點擊“刷新”按鈕時,浏覽器會忽略緩存繼續向服務器發送請求,這時 Last-Modified/ETag将能夠很好利用304,從而減少響應開銷。
2.2.4 哪些請求不能被緩存?
無法被浏覽器緩存的請求:
(1)HTTP信息頭中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告訴浏覽器不用緩存的請求
(2)需要根據Cookie,認證信息等決定輸入内容的動态請求是不能被緩存的
(3)經過HTTPS安全加密的請求(有人也經過測試發現,ie其實在頭部加入Cache-Control:max-age信息,firefox在頭部加入Cache-Control:Public之後,能夠對HTTPS的資源進行緩存,參考《HTTPS的七個誤解》
(4)POST請求無法被緩存
(5)HTTP響應頭中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的請求無法被緩存
3. 使用緩存流程
一個用戶發起一個靜态資源請求的時候,浏覽器會通過以下幾步來獲取并展示資源:
緩存行為主要由緩存策略決定,而緩存策略由内容擁有者設置。這些策略主要通過特定的HTTP頭部來清晰地表達。
以上過程也可以被概括為三個階段:
(1)本地緩存階段:先在本地查找該資源,如果有發現該資源,而且該資源還沒有過期,就使用這一個資源,完全不會發送http請求到服務器;
(2)協商緩存階段:如果在本地緩存找到對應的資源,但是不知道該資源是否過期或者已經過期,則發一個http請求到服務器,然後服務器判斷這個請求,如果請求的資源在服務器上沒有改動過,則返回304,讓浏覽器使用本地找到的那個資源;
(3)緩存失敗階段:當服務器發現請求的資源已經修改過,或者這是一個新的請求(在本來沒有找到資源),服務器則返回該資源的數據,并且返回200, 當然這個是指找到資源的情況下,如果服務器上沒有這個資源,則返回404。
4. 用戶操作行為與緩存的關系
用戶在使用浏覽器的時候,會有各種操作,比如輸入地址後回車,按F5刷新等,這些行為會對緩存有什麼影響呢?
通過上表我們可以看到,當用戶在按 F5進行刷新的時候,會忽略Expires/Cache-Control的設置,會再次發送請求去服務器請求,而Last-Modified/Etag還是有效的,服務器會根據情況判斷返回304還是200;
而當用戶使用 Ctrl F5進行強制刷新的時候,隻是所有的緩存機制都将失效,重新從服務器拉去資源。
(1)普通刷新 – 當按下F5或者點擊刷新按鈕來刷新頁面的時候,浏覽器将繞過本地緩存來發送請求到服務器, 此時, 協商緩存是有效的
(2)強制刷新 – 當按下ctrl F5來刷新頁面的時候, 浏覽器将繞過各種緩存(本地緩存和協商緩存), 直接讓服務器返回最新的資源
(3)回車或轉向 – 當在地址欄上輸入回車或者按下跳轉按鈕的時候, 所有緩存都生效
5. 如何從緩存角度改善站點
(1)同一個資源保證URL的穩定性
(2)給css、js、圖片等資源增加HTTP緩存頭,并強制入口html不被緩存
(3)減少對Cookie的依賴
(4)多用Get方式請求動态Cgi
(5)動态CGI也是可以被緩存
看完如果對你有所幫助記得轉發
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!