緩存普遍存在於咱們的平常上網過程當中。使用緩存主要有幾個好處:web
一是可以減輕服務器端的訪問壓力;數組
二是使用本地緩存可以加快頁面的載入速度,提高用戶體驗。瀏覽器
在瞭解如何使用緩存來優化咱們的web應用以前,咱們先來看看web緩存具體有哪些分類:緩存
瀏覽器能夠將一些比較消耗帶寬並且幾乎不會變動的靜態資源緩存在本地,當用戶須要再次使用這部分資源(好比用戶在點擊瀏覽器中的頁面前進或後退按鈕等)時,就能夠直接從瀏覽器緩存中加載,而不須要再向服務器發起請求。bash
典型表明就是反向代理服務器緩存,反向代理服務器大多數時候就是在分擔服務器端的訪問壓力,能儘可能減小向源服務器發送請求就儘可能減小,能儘量地利用緩存下來的資源就儘量地利用。一些大型站點會使用CDN
,目的是爲了讓用戶就近訪問,加快頁面的載入速度,而在每一個CDN節點一樣也會緩存用戶訪問過的資源,所以也屬於服務器端緩存的範疇。服務器
要實現瀏覽器和服務器對用戶重複訪問的資源進行緩存控制,主要有兩種途徑:優化
一種是經過設置 <meta>
標籤來控制:ui
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
複製代碼
注意上面兩條指令的做用是不容許瀏覽器緩存當前頁面以及頁面上引用的資源,強制瀏覽器每次請求當前頁面時都須要從服務器端獲取最新版本。這種方式僅對部分瀏覽器有效,並且不影響代理服務器對該頁面的緩存控制,緣由是由於代理服務器並不會去解析頁面上的內容。spa
另一種應用更加普遍的方法就是經過 http 協議的頭部字段進行緩存的控制。而經過 http 頭部字段進行控制又能夠從兩個角度來控制緩存:分別是新鮮度(對應 Cache-Control
和 Expires
)和校驗值(對應 Last-Modified
和 Etag
)。其實緩存控制就是在關注這樣兩個問題:一方面是能夠緩存多長時間(新鮮度),另外一方面則是如何判斷緩存失效(校驗)。代理
Cache-Control
/ Expires
這一組頭部字段均可以用來指定緩存的有效期,區別在於前者除了能夠指定緩存有效期(經過設置max-age參數,該參數值和Expires具體含義還不相同,前者指定緩存時長,然後者指定緩存過時的時間點)以外,還能夠實現更加精細的緩存控制功能;然後者只能單一地設置緩存的有效期。
Cache-Control 是一個通用首部,而且在請求頭和響應頭使用的參數還略微有些差別。下面就具體介紹一下 Cache-Control 能夠設置的參數都有哪些以及它們所表明的含義(此處僅介紹出如今服務器端響應中的 Cache-Control 可能會用到的參數)。
max-age=<num>
: 前面提到過了,這裏再也不贅述。單位:秒s-max-age=<num>
: 做用和 max-age 相似,區別在於該參數僅對提供共享緩存的公共代理服務器起做用no-store
:不容許客戶端和緩存服務器對響應進行緩存,意味着每次都會從新向源服務器發起請求(注意不是條件請求)no-cache
:應用這個值時,客戶端和緩存服務器在使用緩存資源以前須要向源服務器發起條件請求確認,相似於max-age=0,注意此時瀏覽器和緩存服務器是能夠緩存響應的public
:此參數是對緩存服務器起做用的,表示容許向多個不一樣的用戶提供同一份緩存(共享緩存)private
:與public
恰好相反,表示當前緩存的內容僅能對當前用戶提供Cache-Control 首部的值能夠由多個參數組合而成,參數之間使用逗號隔開。
Expires
首部用於指定緩存失效的時刻,時間是以服務器上的時間爲準。
服務器能夠經過Last-Modified響應首部來指明當前訪問資源最近一次修改是在何時,客戶端在發送請求校驗資源是否發生修改時,能夠經過If-Modified-Since請求首部向服務器端確認資源在給定時間點以後是否發生更改,服務器能夠根據比對資源的最近一次修改時間和If-Modified-Since首部指定的時間來決定返回304狀態碼仍是返回新的資源。
使用Last-Modified/If-Modified-Since比對文件修改時間的這套機制存在的問題就是:
由於Last-Modified指定的修改時間是精確到秒級的,若是服務器上的文件在一秒內發生屢次更改,單純依靠文件修改時間就檢測不到文件已經發生變化
若是文件在某個時間段內發生屢次更改,可是先後文件內容並無發生變化,這時依靠文件修改時間去判斷文件已經發生修改也不合適
而經過Etag響應首部就可以解決上面提到的問題。經過對當前文件內容計算生成一個惟一標識,經過比對標識是否相同來判斷文件內容是否發生變化。相比於比較文件修改時間,這種方式更加有效。客戶端在發送條件請求時,會包含 If-None-Match
請求首部,來判斷文件內容是否發生變化。
除了可使用上面提到的這些首部來控制緩存以外,另外還有一個古老的響應首部就是 Pragma
。Pragma 首部的值只有一個可選值就是 no-cache
,含義和 Cache-Control: no-cache 是同樣的。可是 Pragma 優先級要高於 Cache-Control,而Cache-Control則又比Expires首部具備更高的優先級。
除了能夠經過 http 首部來控制緩存以外,在瀏覽器中不一樣的操做行爲一樣也會影響瀏覽器是否使用緩存。
當用戶點擊前進或後退按鈕,不管服務器響應的Cache-Control是什麼值(no-store
除外),瀏覽器都會直接使用硬盤中緩存的內容。
在Cache-Control/Expires指定的有效期內若是用戶輸入URL地址以後回車(包括點擊頁面的刷新按鈕或者 F5
),此時瀏覽器會直接使用硬盤中的緩存內容(以下圖),而不會向服務器發起請求。而此時若是緩存期限已過,而以前服務器響應中包含 Last-Modified/Etag 首部(通常服務器返回的響應都會包含這兩個首部,不須要額外的配置),則會向服務器發起條件請求,若是服務器端內容沒有發生更改,則會響應 304
狀態碼,提示瀏覽器緩存有效。
當點擊 Ctrl+F5
時,即便緩存的資源依然有效(仍然在 Cache-Control 首部包含的 max-age 參數指定的期限以內),瀏覽器也會向服務器發起請求(注意此時的請求就不是條件請求了,而是強制從服務器獲取最新的內容)。
文章中咱們主要探討了如何經過 http 首部來控制瀏覽器端緩存,主要能夠歸納爲如下幾點:
Cache-Control 能夠精細地控制緩存,可是須要注意的一點是,它是在 HTTP/1.1 中才出現的,若是須要兼容舊版本,在指定緩存時長時能夠和 Expires 首部一塊兒搭配使用,若是要指定爲 no-cache 則能夠和 Pragma 首部一塊兒使用
不一樣的瀏覽器操做行爲一樣會影響瀏覽器是否使用本地緩存,有些行爲(好比點擊前進後退按鈕)會直接從瀏覽器緩存中返回內容,有些行爲(好比當緩存過時時點擊刷新按鈕等)則會致使瀏覽器發送條件請求確認資源是否更新
優先使用Etag/If-None-Match來校驗資源是否有效