1. 程式人生 > >【拿來主義】當我們談WEB緩存的時候,我們在談些什麽?

【拿來主義】當我們談WEB緩存的時候,我們在談些什麽?

1.0 服務器端 過程 用戶 重定向 new nac java style

第一部分 Web緩存是什麽

場景1:測試妹子測功能時會說為什麽我的瀏覽器的顯示亂七八糟,我的界面怎麽跟別人瀏覽器上不一致?旁邊的人會提醒說:清下緩存試試。

場景2:開發改了代碼,上了環境,發現不生效,這時候首先就是清緩存,清了瀏覽器緩存發現還是不行,再檢查,發現是反向代理緩存。

那麽,當我們談WEB緩存的時候,我們說的是什麽?什麽地方可以緩存?什麽時候用什麽緩存?使用不當會帶來什麽問題,我們怎麽避免?

會不會傻傻分不清楚,那我們就來理一理,看看web緩存究竟是什麽?

緩存:緩存就是把數據或者我們需要取到的內容,放到能更快訪問的地方。緩存對於前端後端的coder來說,應該都不陌生,不論前端後端,我們使用緩存都是為了提升性能。

Web緩存:按照上面的邏輯,就是為了提升Web頁面訪問的性能,把能緩存的頁面or數據緩存到能夠更快取得的地方。廣義的Web緩存也可以包括服務器緩存,本文為了與服務器緩存區分,不包含服務器緩存。

第二部分 Web緩存的類型

在典型的web應用中,一個瀏覽器發起的請求,會經過下圖中的幾個步驟(其中CDN、反向代理是可選的),那麽緩存的地方或者層次也很好理解,就是下圖中的瀏覽器、反向代理、cdn。

技術分享

技術分享技術分享

第三部分 瀏覽器緩存

瀏覽器緩存是所有WEB應用都會使用的,瀏覽器的緩存類型很多,我們可以通過瀏覽器提供的開發者工具來查看。

以chrome瀏覽器為例,打開chrome開發者工具,再選擇“Resources”中看到所有的緩存類型,如下圖所示:

技術分享技術分享

一、Frames

Frames的緩存,是基於HTTP協議的瀏覽器文件級緩存。

瀏覽器在發送文件請求時,可以根據協議頭判斷從服務器端請求文件還是從本地緩存讀取文件,主要判斷依據是expires和etag,讀取文件的流程如下圖:

技術分享技術分享

從這張流程圖可以看出,影響瀏覽器的文件緩存主要有幾個屬性:expires、Etag、Last-Modified,這三個屬性是由http協議定義的。

(一)控制緩存的屬性

在http1.0中約定用expires來確定是否使用緩存中的文件。http1.1中約定使用的是Cache-Control、Last-Modified/If-Modified-Since、etag。下面來分別看下各種屬性的定義:

1、Expires

用於設置靜態資源的過期時間。

2、Cache-Control

Cache-Control可以用於控制是否緩存、緩存的讀取權限、資源的有效期。只不過Cache-Control的選擇更多,設置更細致,如果同時設置的話,其優先級高於Expires。

(1)public 指示響應數據可以被任何客戶端緩存

(2)private 指示響應數據可以被非共享緩存所緩存。這表明響應的數據可以被發送請求的瀏覽器緩存,而不能被中介所緩存

(3)no-cache 指示響應數據不能被任何接受響應的客戶端所緩存

(4)no-store 指示所傳送的響應數據除了不能被緩存,也不能存入磁盤。一般用於敏感數據,以免數據被復制。

(5)must-revalidate 指示所有的緩存都必須重新驗證,在這個過程中,瀏覽器會發送一個If-Modified-Since頭。如果服務器程序驗證得出當前的響應數據為最新的數 據,那麽服務器應當返回一個304 Not Modified響應給客戶端,否則響應數據將再次被發送到客戶端。

(6)proxy-revalidate 與must-revalidate相似,不同的是用來指示共享緩存。

(7)max-age:(單位秒) 數據經過max-age設置的秒數後就會失效,相當於HTTP/1.0中的Expires頭。如果在一次響應中同時設置了max-age和Expires,那麽max-age將具有較高的優先級。(註:ngnix設置expires會被轉換為max-age)

3、Last-Modified/If-Modified-Since

l Last-Modified:標示這個響應資源的最後修改時間。web服務器在響應請求時,告訴瀏覽器資源的最後修改時間。

l If-Modified-Since:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Last-Modified聲明,則再次向web服務器請求時帶上頭 If-Modified-Since,表示請求時間。web服務器收到請求後發現有頭If-Modified-Since 則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說明資源又被改動過,則響應整片資源內容(寫在響應消息包體內),HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應HTTP 304 (無需包體,節省瀏覽),告知瀏覽器繼續使用所保存的cache。

4、Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。

Etag:web服務器響應請求時,告訴瀏覽器當前資源在服務器的唯一標識(生成規則由服務器定義)。nginx中,etag會默認增加,如果需要關閉,需要在配置文件中設置:etag off;

l If-None-Match:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Etage聲明,則再次向web服務器請求時帶上頭If-None-Match (Etag的值)。web服務器收到請求後發現有頭If-None-Match 則與被請求資源的相應校驗串進行比對,決定返回200或304。

(二)用戶行為與緩存

瀏覽器緩存行為還有用戶的行為有關

用戶操作 Expires/Cache-Control Last-Modified/Etag
地址欄回車 有效 有效
頁面鏈接跳轉 有效 有效
新開窗口 有效 有效
前進、後退 有效 有效
F5刷新 無效 有效
Ctrl+F5刷新 無效 無效

(二)如何控制緩存

設置緩存的兩種方式:

1、web服務器配置

以ngnix為例,在nginx.conf中設置:

location~ .*\.(gif|jpg|png|htm|html|css|js|flv|ico|swf)(.*) {

expires 1d;

}

上述配置表示這些靜態文件1天後過期。如果想配置為完全不緩存,那麽可以設置為expires -1;(後面的數字配置為負數),返回的header會被設置為Cache-Control:no-cache

2、後臺代碼寫入

例如:

response.setHeader("Cache-Control", "no-cache");

3、html 的meta標簽

<meta http-equiv="Cache-Control" content="max-age=7200" />

(三)緩存的問題和解決辦法

1、引入緩存之後,主要有兩個問題:

(1)瀏覽器不知道有資源更新,還是使用緩存中的老文件。

(2)各個文件緩存策略不一致,有關聯關系的文件,有的從服務器加載,有的直接取瀏覽器緩存的,這樣有可能會導致界面混亂。

2、解決方式

(1)Etag或Last-modified

Etag是服務端根據文件信息生成的字符串,當服務端文件更新時,Etag也會變化,這樣能保證當服務端文件更新時,取到新的文件內容。

但是Etag這種解決方式的問題是,請求還是會發到服務端,由服務端進行判斷。

Last-modified與Etag類似。

(2)文件名後綴

構建過程中,把構建生成的文件加上隨機後綴,主入口html中的引用文件在構建中替換為增加了文件名後綴的;主入口文件配置為不緩存。

當服務端更新文件時,由於文件名後綴更改,瀏覽器緩存匹配不上,會直接到服務端獲取,服務端沒有更新文件時,在瀏覽器緩存獲取。

這種方式效果較好,但是需要引入構建,對於已經使用了前端構建的web應用比較適用。

二、cookie

cookie是一種能夠讓網站服務器把少量數據儲存到客戶端的硬盤或內存,或是從客戶端的硬盤讀取數據的一種技術。當我們瀏覽某網站時,由Web服務器置於你硬盤上的一個非常小的文本文件,它可以記錄用戶ID、密碼、瀏覽過的網頁、停留的時間等信息。

cookie以鍵值對的方式來存儲,有數量和大小的限制,數量各個瀏覽器不同,大小不能超過4K。

(一)設置cookie的方式:

1、瀏覽器

瀏覽器提供了操作cookie的方式,可以對cookie進行設置、讀取、刪除。另外,cookie也可以設置過期時間。

瀏覽器獲取cookie的方式:

document.cookie

2、服務器

很多時候,我們會使用cookie來做協助做會話管理,登錄成功後,由服務端將sessionid信息寫入cookie,後續客戶端發送的所有請求都攜帶cookie信息,服務端驗證cookie中的sessionid信息,判斷此請求是否合法。以java為例,服務端寫入cookie的方法如下:

Cookie cookie = new Cookie("sessionid",URLEncoder.encode("fejerwiie2234","UTF-8")); response.addCookie(cookie);

(二)cookie的屬性

屬性名稱 屬性含義
name cookie的名稱
value cookie的值
domain 可以訪問此cookie的域名
path 可以訪問此cookie的頁面路徑。
如domain是abc.com,path是/test,那麽只有/test路徑下的頁面可讀取此cookie
expires/Max-Age 字段為此cookie超時時間。若設置其值為一個時間,那麽當到達此時間後,此cookie失效。不設置的話默認值是Session,意思是cookie會和session一起失效。當瀏覽器關閉(不是瀏覽器標簽頁,而是整個瀏覽器) 後,此cookie失效
Size 此cookie大小
httponly cookie的httponly屬性。若此屬性為true,則只有在http請求頭中會帶有此cookie的信息,而不能通過document.cookie來訪問此cookie。
secure 設置是否只能通過https來傳遞此條cookie

三、localStorage

localstorage是Html5中新加入的特性,引入localstorage主要是作為瀏覽器本地存儲,解決cookie作為存儲容量不足的問題。localstorage是一種持久化的存儲。

同樣,localstorage也是一個key-value形式的存儲。

(一)瀏覽器提供了localstorage的增刪改查方法

增加/修改:window.localStorage.setItem("username","admin");

查詢:window.localStorage.getItem("username");

刪除:window.localStorage.removeItem("username","admin");

(二)使用localstorage的註意事項

localstorage中存儲的value只能是字符串型,如果要存儲對象,需要轉換為字符串再進行保存。

四、sessionStorage

sessionStorage用於本地存儲一個會話(session)中的數據,這些數據只有在同一個會話中的頁面才能訪問並且當會話結束後數據也隨之銷毀。因此sessionStorage不是一種持久化的本地存儲,僅僅是會話級別的存儲。

同樣,瀏覽器也提供了sessionStorage的增刪改查方法,與localStorage一致,只是獲取方法為:window.sessionStorage。

五、IndexedDB

IndexedDB也是html5提供的,能夠在客戶端存儲大量的結構化數據的數據庫,並且提供API進行高效檢索。IndexedDB的初始大小是50M,還可以增加,就存儲量來說,秒殺其他存儲方式。

但是它的缺點也很明顯,IndexedDB並不是所有主流瀏覽器都支持,比如IE9、IE10和IE11都不支持,所以,如果你的用戶群還使用著IE系列的瀏覽器,IndexedDB就不用考慮了。

IndexedDB也有一些api,這裏不再詳述了,可以參考:

https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API

六、Web SQL

此方案在W3C已經廢棄,不再維護,替代方案是IndexedDB。

七、application cache

該特性已經從 Web 標準中刪除。

八、Cache Storage

該方案是一個實驗性的方案,並不是所有瀏覽器都支持。

CacheStorage是在ServiceWorker的規範中定義的。CacheStorage 可以保存每個serverWorker申明的cache對象,cacheStorage有open、match、has、delete、keys五個核心方法,可以對cache對象的不同匹配進行不同的響應。

九、Services Worker

service worker提供了很多新的能力,使得web app擁有與native app相同的離線體驗、消息推送體驗。service worker也是一個實驗性的方案,並不是所有瀏覽器都支持。

Service worker可以:

  1. 後臺消息傳遞

  2. 網絡代理,轉發請求,偽造響應

  3. 離線緩存

  4. 消息推送

可以參考:https://developer.mozilla.org/zh-CN/docs/Web/API/Service_Worker_API/Using_Service_Workers

第三部分、CDN緩存

網站的加載速度,除了資源的多少和大小外,很大部分時間是用於網絡傳輸的,而網絡傳輸時間與用戶瀏覽器與資源所在服務器的地理位置直接相關,要提升網站加載速度,一個辦法就是使資源所在服務器與用戶的地理位置盡量靠近。

CDN:全稱是Content Delivery Network,即內容分發網絡。其基本思路是盡可能避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快、更穩定。CDN包括分布式存儲、負載均衡、網絡請求的重定向和內容管理4個要件。而其中呢,內容管理和全局的網絡流量管理是CDN的核心所在。CDN確保內容以一種極為高效的方式為用戶的請求提供服務,使用戶可就近取得所需內容,解決 Internet網絡擁擠的狀況,提高用戶訪問網站的響應速度。

CDN的拓撲圖如下:

技術分享技術分享

一、CDN的緩存機制

  CDN邊緣節點緩存策略因服務商不同而不同,但一般都會遵循http標準協議,通過http響應頭中的Cache-control: max-age的字段來設置CDN邊緣節點數據緩存時間。當客戶端向CDN節點請求數據時,CDN節點會判斷緩存數據是否過期,若緩存數據並沒有過期,則直接將緩存數據返回給客戶端;否則,CDN節點就會向源站發出回源請求,從源站拉取最新數據,更新本地緩存,並將最新數據返回給客戶端。所以,如果我們修改了內容,最好加個版本號,讓CDN重新獲取資源,從而減少不必要的麻煩。

  CDN服務商一般會提供基於文件後綴、目錄多個維度來指定CDN緩存時間,為用戶提供更精細化的緩存管理。CDN緩存時間會對“回源率”產生直接的影響。若CDN緩存時間較短,CDN邊緣節點上的數據會經常失效,導致頻繁回源,增加了源站的負載,同時也增大的訪問延時;若CDN緩存時間太長,會帶來數據更新時間慢的問題。開發者需要增對特定的業務,來做特定的數據緩存時間管理。

二、CDN的問題

CDN的分流作用不僅減少了用戶的訪問延時,也減少了源站的負載。

但其缺點主要是緩存的同步問題:當網站更新時,如果CDN節點上數據沒有及時更新,即便用戶再瀏覽器使用Ctrl +F5的方式使瀏覽器端的緩存失效,也會因為CDN邊緣節點沒有同步最新數據而導致用戶訪問異常。

三、如何解決CDN的問題

CDN的主要問題是由於緩存同步不及時帶來的,緩存更新有兩種方式:

(一)定制緩存策略

靜態文件在返回時由源服務器控制expires、cache-control等屬性來定義CDN的緩存策略。

(二)源服務器資源更新時,主動刷新CDN緩存

CDN邊緣節點對開發者是透明的,相比於瀏覽器Ctrl+F5的強制刷新來使瀏覽器本地緩存失效,開發者可以通過CDN服務商提供的“刷新緩存”接口來達到清理CDN邊緣節點緩存的目的。這樣開發者在更新數據後,可以使用“刷新緩存”功能來強制CDN節點上的數據緩存過期,保證客戶端在訪問時,拉取到最新的數據。

第四部分、反向代理緩存

反向代理(Reverse Proxy): 這種機制是Web服務器隱藏在代理服務器之後,實現這種機制的服務器稱作反向代理服務器(Reverse Proxy Server)。此時,Web服務器成為後端服務器,反向代理服務器稱為前端服務器。

引入反向代理服務器的目的之一就是基於緩存的加速。我們可以將內容緩存在反向代理服務器上,所有緩存機制的實現仍然采用HTTP/1.1協議。

(一)反向代理緩存配置

以通常使用的反向代理--ngnix為例,實現緩存的配置如下:

1、proxy_cache_path

語法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];

默認值:None

使用字段:http

指令指定緩存的路徑和一些其他參數,緩存的數據存儲在文件中,並且使用代理url的哈希值作為關鍵字與文件名。levels參數指定緩存的子目錄數,例如:

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;

文件名類似於:

/data/nginx/cache/c/29/b7f54b2df7773722d382f4809d65029c

levels指定目錄結構,可以使用任意的1位或2位數字作為目錄結構,如 X, X:X,或X:X:X 例如: “2”, “2:2”, “1:1:2“,但是最多只能是三級目錄。

2、proxy_cache

語法:proxy_cache zone_name;

默認值:None

使用字段:http, server, location

設置一個緩存區域的名稱,一個相同的區域可以在不同的地方使用。

3、proxy_cache_valid

語法:proxy_cache_valid reply_code [reply_code …] time;

默認值:None

使用字段:http, server, location

為不同的應答設置不同的緩存時間,例如:

proxy_cache_valid 200 302 10m;

proxy_cache_valid 404 1m;

為應答代碼為200和302的設置緩存時間為10分鐘,404代碼緩存1分鐘。

如果只定義時間:

proxy_cache_valid 5m;

那麽只對代碼為200, 301和302的應答進行緩存。

同樣可以使用any參數任何應答。

proxy_cache_valid 200 302 10m;

proxy_cache_valid 301 1h;

proxy_cache_valid any 1m;

參考地址不明

【拿來主義】當我們談WEB緩存的時候,我們在談些什麽?