首頁»前端»通過HTTP Header控制緩存

通過HTTP Header控制緩存

來源:segmentfault 發布時間:2019-05-15 閱讀次數:

  我們經常通過緩存技術來加快網站的訪問速度,從而提升用戶體驗。HTTP協議中也規定了一些和緩存相關的Header,來允許瀏覽器或共享高速緩存緩存資源。這些Header包括:

  • Last-Modified 和 If-Modified-Since
  • ETag 和 If-None-Match
  • Expires
  • Cache-Control

  以上Header又可以分成兩種類型:

  • 協商緩存:瀏覽器發送驗證到服務器,由服務器決定是否從緩存中讀取,如 1 和 2 。
  • 強緩存:瀏覽器驗證緩存的有效性,然后決定是否從緩存中讀取數據,如 3 和 4 。

  本文將會分別介紹這四種配置的作用以及可能產生的影響。

  1、Last-Modified 和 If-Modified-Since

  Last-Modified:服務器在響應請求時,告知瀏覽器資源的最后修改時間。

  If-Modified-Since:瀏覽器再次發送請求時,會通過此Header通知服務器在上次請求時所得到的資源最后修改時間。服務器會將If-Modified-Since與被請求資源的最后修改時間進行比對。若資源的最后修改時間晚于If-Modified-Since,表示資源已被改動,則響最新的資源,返回200狀態碼;若資源的最后修改時間早于或等于If-Modified-Since,表示瀏覽器端的資源已經是最新版本,響應304狀態碼,通知瀏覽器繼續使用緩存中的資源。

  2、ETag 和 If-None-Match

  ETag:服務器分配給資源的唯一標識符,資源被修改后,ETag也會隨之發生變化。

  If-None-Match:瀏覽器再次發送請求時,會通過此Header通知服務器已緩存資源的ETag。服務器會將If-None-Match與被請求資源的最新ETag進行比對。若不相同,表示資源已被改動,則響應最新的資源,返回200狀態碼;若值相同,則直接響應304狀態碼,通知瀏覽器繼續使用緩存中的資源。

  3、Expires

  服務器可以通過此Header向瀏覽器傳遞一個具體的時間(格林威治格式,例如:Thu, 19 Jul 2018 07:43:05 GMT) ,來明確地宣告資源的有效期。在資源過期之前,瀏覽器不再發送請求,而是直接從緩存中讀取數據。只有當資源過期之后,瀏覽器才會再次向服務器請求該資源。

  4、Cache-Control

  服務器使用此Header來向客戶端建議緩存策略,它有一下幾個可選值:

  max-age=秒:告知瀏覽器緩存的有效時長,在該時間內瀏覽器將直接從緩存中讀取數據。

  s-maxage=秒:作用同max-age,但是只對共享高速緩存(如CDN)有效,對瀏覽器無效。

  no-cache:告知瀏覽器不要直接使用緩存,而是必須向服務器發送請求。

  no-store:告知瀏覽器不要緩存本次請求和響應的任何信息。

  public:宣告任何緩存媒介都可以緩存該響應。

  private:宣告該響應只允許個體客戶端(如瀏覽器)去緩存,而不允許共享高速緩存(如CDN)去緩存。

  在上面的介紹中我們了解到瀏覽器會根據max-age設置的時間進行緩存。而通過研究發現CDN也會識別源站響應頭中Cache-Control屬性,根據max-age設置的時間進行緩存,但是,如果源站同時設置了s-maxage和max-age,那么CDN會優先采用s-maxage。

  下面通過圖例來展示一下這些可選值的效果。

  首先了解一下瀏覽器是怎樣根據max-age進行緩存的:

  從上圖不難發現,服務器在Header中返回了Cache-Control: max-age=100后,瀏覽器成功緩存100秒,該時間段內的請求都從直接以本地緩存來響應。

  那么,服務器在Header中返回Cache-Control:s-maxage=100時,又會對瀏覽器產生什么樣的影響呢?

  如上圖所示,瀏覽器沒有采取任何緩存策略,這是因為s-maxage面向的是共享高速緩。

  上面這兩個例子很容易理解,在現實世界中,為了加快網站響應速度,我們可能會在瀏覽器和服務器之間引入CDN服務。瀏覽器的請求會先到達CDN,然后CDN判斷是從緩存中讀取數據還是回源到服務器。接下來,讓我們看看max-age和s-maxage會對CDN的緩存策略帶來哪些影響。

  可以看出CDN也會利用max-age來緩存,所以在100秒內強制刷新瀏覽器時,CDN會直接用緩存來響應。

  如果服務器使用了s-maxage又會如何呢?

  不難發現CDN對max-age和s-maxage采取了同樣的緩存策略,但瀏覽器并不會根據s-maxage來進行緩存。

  CDN供應商的特殊規則

  我們分別測試了阿里云和騰訊云的CDN對Cache-Control的支持情況,發現他們都有一些獨特的規則。

  阿里云CDN可以在控制臺里設置Cache-Control,該設置會覆蓋源服務器的Cache-Control。

  騰訊云CDN雖然沒有再控制臺提供覆蓋Cache-Control的功能,但其規則卻一點也不簡單,在使用的時候一定要特別注意:

  • 服務器和CDN均不對緩存進行配置時,CDN會采用默認的緩存機制(靜態文件緩存30天,動態請求不緩存);
  • CDN配置緩存機制(但并未開啟高級緩存配置)且服務器設置Cache-Control: s-maxage=200,max-age=100時,CDN會按照其控制臺設置的規則進行緩存,瀏覽器則按照max-age進行緩存;
  • 服務器不設置Cache-Control時,CDN會自動在響應的Header中添加Cache-Control: max-age=600,這就會讓瀏覽器將該資源緩存600秒;
  • 服務器設置為禁用緩存時,CDN和瀏覽器均不進行緩存;
  • 服務器設置Cache-Control: s-maxage=200,max-age=100并開啟CDN的高級緩存配置時,CDN會從s-maxage和控制臺中設置的緩存時間中選擇最小值來作為緩存時間,而瀏覽器則始終使用max-age;
  • 服務器設置Cache-Control:max-age=100并開啟CDN的高級緩存配置時,CDN會從max-age和控制臺中設置的緩存時間中選擇最小值來作為緩存時間,不影響瀏覽器的緩存策略。

  組合使用

  如果同時設置了這些Header,瀏覽器和高速共享緩存會按照下面的優先級進行緩存:

  Cache-Control > Expires > ETag > Last-Modified

  也就是說,Cache-Control不僅是強緩存,而且擁有最高的優先級,我們可以為不經常發生變化的資源應用該Header來提升響應時間。

  在Ada中使用緩存

  Ada提供了UI腳手架和API腳手架,這兩類腳手架的服務器端入口文件分別為index.server.js和index.js,我們只需要在入口文件的請求處理函數中為響應添加適當的Header,即可通知客戶端進行響應的緩存,比如:

  // 設置CDN緩存300秒,瀏覽器緩存200秒

  ctx.response.headers.set('Cache-Control', public,s-maxage=300,max-age=200)

  在為請求添加緩存Header之前,應該先為其制定適當的緩存策略,需要考慮該URL是否適合緩存(數據是否特定于用戶)以及需要緩存的時長等等。

  總結

  通過使用這些HTTP Header,我們可以主動影響瀏覽器甚至CDN的緩存策略,從而減少請求數量,提升網頁性能,減輕服務器壓力。

  Ada的靈活機制能讓我們為不同的URL設置不同的緩存策略,能夠更有針對性地進行主動緩存。

QQ群:WEB開發者官方群(515171538),驗證消息:10000
微信群:加小編微信 849023636 邀請您加入,驗證消息:10000
提示:更多精彩內容關注微信公眾號:全棧開發者中心(fsder-com)
網友評論(共0條評論) 正在載入評論......
理智評論文明上網,拒絕惡意謾罵 發表評論 / 共0條評論
登錄會員中心
大发国际网址 勃利县| 平果县| 高尔夫| 抚松县| 曲阜市| 越西县| 辽宁省| 上饶市| 千阳县| 安图县| 白银市| 澄迈县| 洞头县| 广水市| 元朗区| 尚义县| 拉萨市| 梨树县| 盐源县| 兰西县| 武清区| 县级市| 顺义区| 平原县| 额敏县| 马鞍山市| 独山县| 江北区| 侯马市| 镇远县| 叙永县| 津南区| 长葛市| 黄山市| 巴中市| 襄汾县| 紫金县| 屯留县| 博客| 邵阳市| 沈丘县| 白玉县| 古丈县| 湘潭县| 会昌县| 宁安市| 大同县| 柘城县| 久治县| 辽阳市| 凤冈县| 方山县| 潮安县| 筠连县| 清水县| 玉田县| 巴中市| 玉树县| 安岳县| 巢湖市| 南靖县| 阿图什市| 当雄县| 盘山县| 萍乡市| 凉城县| 宣汉县| 旬邑县| 长顺县| 准格尔旗| 灵丘县| 建德市| 鹤岗市| 荥阳市| 辽宁省| 汉源县| 楚雄市| 工布江达县| 铁岭市| 林甸县| 历史| 道孚县| 资讯| 辽阳市| 邻水| 灵寿县| 平舆县| 长垣县| 平度市| 巴楚县| 沂源县| 阳曲县| 盘山县| 麦盖提县| 会宁县| 太白县| 关岭| 永福县| 夏津县| 南投县| 渭南市| 绥芬河市| 泾源县| 微山县| 邹城市| 克什克腾旗| 射阳县| 崇明县| 博兴县| 永宁县| 慈利县| 阿克苏市| 闻喜县| 洞口县| 白玉县| 海门市| 龙门县| 鄄城县| 徐闻县| 南宫市| 烟台市| 霍邱县| 景东| 西乌珠穆沁旗| 疏附县| 鄂温| 礼泉县| 科尔| 镇远县| 札达县| 六枝特区| 化州市| 延庆县| 塔城市| 中牟县| 阜平县| 内江市|