http緩存與cdn緩存配置指南

騰訊DeepOcean原創文章:dopro.io/http-cache-…css

 

配置http緩存與cdn緩存一直以來都是web性能優化中重要而常見的手段。合理的http緩存與cdn緩存配置能夠起到減輕服務器壓力,緩解網絡瓶頸,提高用戶體驗等做用,不當的緩存配置卻會致使資源沒法及時更新,用戶體驗差別,甚至流程出錯等問題。本文主要講解http緩存與cdn緩存的原理和配置規則,但願經過本文的講解可以讓你們清楚什麼是合理的緩存配置,如何爲本身的項目定製化緩存方案,以及若是碰到緩存問題,應該如何分析解決。html

首先,讓咱們來看這樣一個場景

項目A上線了一個新特性,包含着邏輯的改動和頁面UI的更新,小明做爲項目開發將代碼提交後進行了預發佈。產品經理小紅開始體驗新特性,奇怪的是,小紅進入項目後卻並無看到最新的特性,這時小明思考了一會說,小紅你點擊刷新再試試,果真,刷新後項目有了變化,新特性出來了,可是這時又有了新的問題,項目裏的圖片彷佛仍是舊圖,小明又思考了一會,隨後在電腦前搗鼓一番,讓小紅再次體驗,終於,這個時候特性完整驗收經過。上述的案例中,其實就包含着http緩存和cdn緩存的應用,固然,這是一個反面教材,實際上線過程當中,咱們不可能讓每個用戶點擊刷新來體驗咱們的新特性,那應該如何解決上述問題呢,接下來上乾貨。前端

http緩存

簡介

http緩存是客戶端緩存,瀏覽器做爲客戶端接受到服務端響應後,對於響應首部字段進行解析,分析出相應的緩存規則,將資源按規則進行緩存,再次請求時若是命中緩存則直接讀取本地緩存再也不發出請求。webpack

緩存規則

http緩存規則由響應首部字段進行控制,其中的關鍵字段有ExpiresCache-ControlLast-ModifiedEtag 四個字段,ExpiresCache-Control用來肯定肯定緩存的存儲時間,Last-ModifiedEtag則用來肯定緩存是否要被更新,咱們簡單來看一下區別。
  • expires: HTTP1.0中用來控制緩存時間的參數,響應頭包含日期/時間, 即在此時間以後,響應過時。
  • cache-control: HTTP1.1中用來控制緩存時間的參數
    • public: 代表響應能夠被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存。
    • private: 代表響應只能被單個用戶緩存,不能做爲共享緩存(即代理服務器不能緩存它)。
    • max-age=<seconds>: 設置緩存存儲的最大週期,相對於請求的時間緩存seconds秒,在此時間內,訪問資源直接讀取本地緩存,不向服務器發出請求。(與expires同時出現時,max-age優先級更高)
    • s-maxage=<seconds>: 規則等同max-age,覆蓋max-age 或者 Expires 頭,可是僅適用於共享緩存(好比各個代理),而且私有緩存中它被忽略。(與expires或max-age同時出現時,s-maxage優先級更高)
    • no-store: 不緩存服務器響應的任何內容,每次訪問資源都須要服務器完整響應
    • no-cache: 緩存資源,但當即過時,每次請求都須要跟服務器對比驗證資源是否被修改。(等同於max-age=0)
  • Last-modified: 源頭服務器認定的資源作出修改的日期及時間。精確度比Etag低。包含有If-Modified-Since或 If-Unmodified-Since首部的條件請求會使用這個字段。
  • Etag: HTTP響應頭是資源的特定版本的標識符。 
咱們經過chrome控制檯能夠很輕鬆的找到一個案例:

http-cdn-example

圖中配置web

  1. cache-control: max-age=31535000 表明相對於請求時間,緩存31536000秒,即365天,在此時間內,再次訪問資源直接讀取本地緩存,不向服務器發送請求.
  2. last-modified: Mon...上次修改時間,若是緩存時間過時,該字段將用於與請求中的If-Modified-Since字段進行對比,一致則繼續使用以前緩存,不一致則認定緩存失效
  3. expires: 在http1.0版本下被cache-control覆蓋,此處意爲緩存至Sat, 11 Aug ...

緩存流程

http-cdn-http-process

緩存規則在其中是如何起做用的呢,咱們來看幾個重點關注部分chrome

重點關注1: 緩存是否過時gulp

基於該資源上次響應緩存規則同時知足下列條件則視爲緩存未過時。須要注意的是,判斷緩存是否過時只跟客戶端有關係,與服務端無關。1&2&3同時知足即認爲緩存未過時,相反則是已過時瀏覽器

  1. cache-control值爲max-age
  2. max-age > 0
  3. 當前 date < 上次請求時的date + max-age
注:expire可同等轉化爲cache-control=max-age形式,再也不贅述,s-maxage與maxage規則相同,再也不贅述

重點關注2: 詢問服務器資源是否修改緩存

判斷資源是否修改,須要客戶端與服務器共同協做,客戶端在首次拿到資源緩存後會存儲Etag(如有)和Last-Modified(如有),在下次緩存過時時會將Etag寫在請求頭部中的If-None-Match中,將Last-Modified值寫在請求頭部中的If-Modified-Since中,服務端優先對Etag進行對比,而後再對比Last-Modified,徹底經過後即視爲緩存沒有修改,有一項不經過則認爲資源已被修改,緩存失效性能優化

重點關注3: 緩存規則

緩存規則主要由cache-control字段和expires字段體現,同時出現則以cache-control爲準具體狀況以下:

  1. cache-control=no-store 不緩存任何資源
  2. cache-control=no-cache 緩存但當即過時
  3. cache-control=max-age(s-maxage) = 0 緩存但當即過時(等同於no-cache)
  4. cache-control=max-age(s-maxage)= seconds (seconds > 0)—— 基於請求時間緩存seconds秒
  5. cache-control=其餘 根據http標準,若是不攜帶任何關於緩存時常的標記,則緩存時間等於當前時間和 Last-Modified時間的差值的10%,等同於cache-control=max-age=(date - Last-Modified)/ 10,經過fiddler抓包可看到英文原文:No explicit HTTP Cache Lifetime information was provided.Heuristic expiration policies suggest defaulting to: 10% of the delta between Last-Modified and Date.
  6. expires = 過去的時間或無效時間,緩存但當即過時,等同於cache-control=no-cache
  7. expires = 將來的時間,緩存到對應時間

緩存配置

從上述規則和與流程圖中咱們能夠看到,緩存規則的配置其實並不複雜,除開Etag和Last-Modified用於緩存對比(實際使用中只須要開啓該功能便可),咱們須要關注的其實只是cache-control(expires可轉化爲max-age形式,再也不贅述),方案以下:
  1. cache-control: no-store:不緩存,每次訪問都從服務下載全部資源。
  2. cache-control: no-cache或cache-control: max-age=0:對比緩存,緩存當前資源,但每次訪問都須要跟服務器對比,檢查資源是否被修改。
  3. cache-control: max-age=seconds //seconds > 0:強緩存,緩存當前資源,在必定時期內,再次請求資源直接讀取本地緩存。
注:強緩存下資源也並不是不可更新,例如chrome的ctrl + f5等同於直接觸發方案1,f5或者webview的刷新鍵會直接觸發方案2,但都是基於客戶端操做,不建議歸入實際項目考慮。

實際項目中,方案1的應用基本上看不到,對比方案2和方案3,方案1沒有任何優點。在方案2和方案3的選擇中,咱們會對資源做區分。

  • 對於img,css,js,fonts等非html資源,咱們能夠直接考慮方案3,而且max-age配置的時間能夠儘量久,相似於緩存規則案例中,cache-control: max-age=31535000配置365天的緩存,須要注意的是,這樣配置並不表明這些資源就必定一年不變,其根本緣由在於目前前端構建工具在靜態資源中都會加入戳的概念(例如,webpack中的[hash],gulp中的gulp-rev),每次修改均會改變文件名或增長query參數,本質上改變了請求的地址,也就不存在緩存更新的問題。
  • 對於html資源,咱們建議根據項目的更新頻度來肯定採用哪套方案。html做爲前端資源的入口文件,一旦被強緩存,那麼相關的js,css,img等均沒法更新。對於高頻維護的業務類項目,建議採用方案2,或是方案3但max-age設置一個較小值,例如3600,一小時過時。對於一些活動項目,上線後不會進行較大改動,建議採用方案3,不過max-age也不要設置過大,不然一旦出現bug或是未知問題,用戶沒法及時更新。
除了以上考慮,有時候其餘因素也會影響緩存的配置,例如QQ紅包除夕活動,高併發大流量很容易給服務器帶來極大挑戰,這時咱們做爲前端開發,就能夠採用方案3來避免用戶屢次進入帶來的流量壓力。

小結

對於http緩存的配置,咱們始終要作到兩點,一是清楚明白http緩存的原理與規則,二是明確緩存的配置不是一次性的,根據不一樣的狀況配置不一樣的規則,纔可以更好的發揮http緩存的價值。

cdn緩存

cdn緩存是一種服務端緩存,CDN服務商將源站的資源緩存到遍及全國的高性能加速節點上,當用戶訪問相應的業務資源時,用戶會被調度至最接近的節點最近的節點ip返回給用戶,在web性能優化中,它主要起到了,緩解源站壓力,優化不一樣用戶的訪問速度與體驗的做用。

緩存規則

與http緩存規則不一樣的是,這個規則並非規範性的,而是由cdn服務商來制定,咱們以騰訊雲舉例,打開cdn加速服務配置,面板以下。http-cdn-cdn-config

 

能夠看到,提供給咱們的配置項只有文件類型(或文件目錄)和刷新時間,意義也很簡單,針對不一樣文件類型,在cdn節點上緩存對應的時間。

cdn運做流程

http-cdn-cdn-process

 

由圖咱們能夠看出,cdn緩存的配置主要做用在緩存處理階段,雖然配置項只有文件類型和緩存時間,但流程卻並不簡單,咱們先來明確一個概念——回源,回源的意思就是返回源站,何爲源站,就是咱們本身的服務器,不少人誤解接入cdn就是把資源放在了cdn上,其實否則,如圖中所示,接入cdn後,咱們的服務器就是源站,源站通常狀況下只會在cdn節點沒有資源或cdn資源失效時接收到cdn節點的請求,其餘時間,源站並不會接收請求(固然,若是咱們知道源站的地址,咱們能夠直接訪問源站)。明確了回源的概念後,cdn的流程就顯得不那麼複雜了,簡單的理解就是,沒有資源就去源站讀取,有資源就直接發送給用戶。與http緩存不一樣的是,cdn中沒有no-cache(max-age=0)的狀況,當咱們設置緩存時間爲0的時候,該類型文件就被認定爲不緩存文件,就是全部請求直接轉發源站,只有當緩存時間大於0且緩存過時的時候,纔會與源站對比緩存是否被修改。

緩存配置

cdn緩存配置並不麻煩,總體來講,建議和http緩存配置保持統一。須要特別注意的是,cdn的緩存配置會受到http緩存配置的影響,並且各個cdn服務商並不徹底一致,以騰訊云爲例,在緩存配置的文檔中特別有如下說明。

http-cdn-cloud-tencent-cache這會對咱們有什麼影響呢?

  1. 若是咱們http緩存設置cache-control: max-age=600,即緩存10分鐘,但cdn緩存配置中設置文件緩存時間爲1小時,那麼就會出現以下狀況,文件被訪問後第12分鐘修改並上傳到服務器,用戶從新訪問資源,響應碼會是304,對比緩存未修改,資源依然是舊的,一個小時後再次訪問才能更新爲最新資源
  2. 若是不設置cache-control呢,在http緩存中咱們說過,若是不設置cache-control,那麼會有默認的緩存時間,但在這裏,cdn服務商明確會在沒有cache-control字段時主動幫咱們添加cache-control: max-age=600
注:針對問題1,也並不是沒有辦法,當咱們必需要在緩存期內修改文件,而且不向想影響用戶體驗,那麼咱們可使用cdn服務商提供的強制更新緩存功能,主要注意的是,這裏的強制更新是更新服務端緩存,http緩存依然按照http頭部規則進行本身的緩存處理,並不會受到影響。

小結

cdn緩存的配置並不複雜, 複雜的狀況在於cdn緩存配置會受到http緩存配置的影響,而且不一樣的cdn運營商對於這種影響的處理也都不一致,實際使用時,建議去對應的cdn服務商文檔中找到對應的注意事項。

http緩存與cdn緩存的結合

當咱們分別理解了http緩存配置和cdn緩存配置後,咱們還有一件事情,就是理解兩者結合時,請求的流向問題

http-cdn-summery

 

當用戶訪問咱們的業務服務器時,首先進行的就是http緩存處理,若是http緩存經過校驗,則直接響應給用戶,若是未經過校驗,則繼續進行cdn緩存的處理,cdn緩存處理完成後返回給客戶端,由客戶端進行http緩存規則存儲並響應給用戶。當咱們分析緩存問題時,必定要將兩個流程獨立開來分析,如今來看開篇時的錯誤案例,很明顯,第一個問題時因爲http緩存配置不合理,致使用戶必須進行強制刷新才能更新資源,第二個問題則是cdn緩存未及時更新形成的。

總結

http緩存和cdn緩存分別做爲客戶端緩存和服務端緩存共同影響着咱們的web請求流向,要想作好緩存配置,首先是清楚緩存的原理和配置規則,其次則是結合項目分析緩存級別,具體狀況具體處理。

歡迎關注"騰訊DeepOcean"微信公衆號,每週爲你推送前端、人工智能、SEO/ASO等領域相關的原創優質技術文章:

看小編搬運這麼辛苦,關注一個唄:)

相關文章
相關標籤/搜索