整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          校導李凡〡瀏覽器緩存那些事兒

          算機科學中最難的兩件事是緩存失效和命名。

          -- Phil Karlton

          今天我們來簡要了解一下瀏覽器的緩存問題。

          瀏覽器緩存是指當瀏覽器請求一個資源的時候,會在本地保存一份副本,當下一個請求來到的時候,如果是相同的URL,緩存會根據緩存機制決定是直接使用副本響應訪問請求,還是向源服務器再次發送請求。

          瀏覽器緩存的作用

          1. 減少網絡帶寬消耗無論對于網站運營者或者用戶,帶寬都代表著金錢,過多的帶寬消耗,只會便宜了網絡運營商。當Web緩存副本被使用時,只會產生極小的網絡流量,可以有效的降低運營成本。

          2. 降低服務器壓力給網絡資源設定有效期之后,用戶可以重復使用本地的緩存,減少對源服務器的請求,間接降低服務器的壓力。同時,搜索引擎的爬蟲機器人也能根據過期機制降低爬取的頻率,也能有效降低服務器的壓力。

          3. 減少網絡延遲,加快頁面打開速度 帶寬對于個人網站運營者來說是十分重要,而對于大型的互聯網公司來說,可能有時因為錢多而真的不在乎。那Web緩存還有作用嗎?答案是肯定的,對于最終用戶,緩存的使用能夠明顯加快頁面打開速度,達到更好的體驗。

          瀏覽器端的緩存規則

          真正的瀏覽器工作的時候并不是將完整的內容保存在本地,各種瀏覽器都有不同的方式,譬如firefox是一種類似innodb的方式存儲的key value 的模式,在地址欄中輸入 about:cache 可以看見緩存的文件,chrome會把緩存的文件保存在一個叫User Data的文件夾下。

          瀏覽器緩存有一套自己的規則,可以用來決定何時使用緩存,何時從服務器上獲取資源,這些規則是在HTTP協議頭和HTML頁面的Meta標簽中定義的。

          1. 響應頭明確說明,我不想被緩存,則不會被緩存;

          2. 如果請求信息是需要認證或者安全加密的(如: HTTPS),相應內容也不會被緩存;

          3. 緩存如果有以下表現,則認為是fresh新鮮的(無需檢查源服務器,直接發送給客戶端),則內容緩存直取,繞過源服務器。

          ★ 含有完整的過期時間和壽命控制頭信息,并且內容仍在保鮮期內。

          ★ 緩存最近已展現,并且在不久前修改。

          4. 若內容陳舊,則會要求源服務器做驗證 validate ,或者告訴緩存其拷貝副本是否是OK的。

          5. 特定情況下——例如,斷網了,之前有過的響應緩存直取而不檢查源服務器。 總而言之,新鮮度 freshness 和校驗 validation 是確定緩存內容是否可用的兩個維度。如果要展示的足夠新,直接使用緩存;如果檢測發現展示內容并未變化,則會直接使用緩存。下面兩張圖很清晰的描述了瀏覽器發起請求時決定是否使用緩存的機制:

          瀏覽器緩存的控制

          1. 使用 Meta 標簽控制頁面緩存

          前端攻城獅可以在HTML頁面的節點中加入標簽,代碼如下:

          <meta http-equiv="Pragma" content="no-cache">

          上述代碼的作用是告訴瀏覽器當前頁面不被緩存,每次訪問都需要去服務器拉取。使用上很簡單,但只有部分瀏覽器可以支持,而且所有緩存代理服務器都不支持,因為代理不解析HTML內容本身。所以并不推薦使用這種方式控制頁面緩存。

          2.使用 HTTP 協議頭控制頁面緩存

          在HTTP請求和響應的消息報頭中,常見的與緩存有關的消息報頭有以下這些:

          Cache-Control 與 Expires

          Cache-Control 與 Expires 的作用一致,都是指明當前資源的有效期,控制瀏覽器是否直接從瀏覽器緩存取數據還是重新發請求到服務器取數據。只不過 Cache-Control 的選擇更多,設置更細致,如果同時設置的話,其優先級高于 Expires。

          Last-Modified/ETag 與 Cache-Control/Expires

          配置 Last-Modified/ETag 的情況下,瀏覽器再次訪問統一 URI 的資源,還是會發送請求到服務器詢問文件是否已經修改,如果沒有,服務器會只發送一個304回給瀏覽器,告訴瀏覽器直接從自己本地的緩存取數據;如果修改過那就整個數據重新發給瀏覽器。

          Cache-Control/Expires 則不同,如果檢測到本地的緩存還是有效的時間范圍內,瀏覽器直接使用本地副本,不會發送任何請求。兩者一起使用時,Cache-Control/Expires 的優先級要高于 Last-Modified/ETag。即當本地副本根據 Cache-Control/Expires 發現還在有效期內時,則不會再次發送請求去服務器詢問修改時間(Last-Modified)或實體標識(Etag)了。

          一般情況下,使用 Cache-Control/Expires 會配合 Last-Modified/ETag 一起使用,因為即使服務器設置緩存時間, 當用戶點擊“刷新”按鈕時,瀏覽器會忽略緩存繼續向服務器發送請求,這時 Last-Modified/ETag 將能夠很好利用304,從而減少響應開銷。

          Last-Modified與ETag

          你可能會覺得使用 Last-Modified 已經足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要 Etag(實體標識)呢?HTTP1.1 中 Etag 的出現主要是為了解決幾個 Last-Modified 比較難解決的問題:

          ★ Last-Modified 標注的最后修改只能精確到秒級,如果某些文件在1秒鐘以內,被修改多次的話,它將不能準確標注文件的新鮮度。

          ★ 如果某些文件會被定期生成,當有時內容并沒有任何變化,但 Last-Modified 卻改變了,導致文件沒法使用緩存。

          ★ 有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形。

          Etag 是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符,能夠更加準確的控制緩存。Last-Modified 與ETag 是可以一起使用的,服務器會優先驗證 ETag,一致的情況下,才會繼續比對 Last-Modified,最后才決定是否返回304。

          瀏覽器緩存機制在實際開發中的應用

          服務器端可以設置緩存規則,但在服務器不能掌控的地方也許會出現一些意外。

          1. 緩存會被擠出。

          所謂緩存被擠出,因為瀏覽器的緩存空間是有限的,所有網站希望緩存的文件都塞在里面,形成一個先進先出的隊列。所以你即使設置了20年的緩存時間,也基本上是不可能保證有那么久的生命期。而且用戶也有可能主動清除瀏覽器緩存,某些系統清理軟件也可能清理瀏覽器緩存。

          2. 文件有可能在運營商服務器上被劫持。

          第二個問題是用戶的寬帶運營商為了提高速度,可能會在自己某節點服務器上緩存你的文件(比如 style.css?v1),好處是當用戶請求這個文件的時候,運營商無需來你的服務器上請求文件,而自己直接就給出了。 如果你的 querys string 更新了(style.css?v2),按照HTTP規范,這理應被視作一個新的文件。

          但是運營商仍然可能會拿自己的緩存,而不是遵循規范。有點可惡對不對?這就是我們在用戶量極大的情況下偵查到的情況,所以,為了保證更新的文件確定能下發到所有的用戶,我們最好是在資源文件改變時,使用前端構建工具修改文件名,而不是僅修改 query string。

          以下是業界公認的最佳規則:

          對于動態生成的html頁面使用HTTP頭:Cache-Control: no-cache

          對于靜態html頁面使用HTTP頭:Last-Modified

          其他所有的文件類型都設置Expires頭,并且在文件內容有所修改的時候修改文件名

          作者簡介:李凡,英文名Levy,校導Web前端工程師,熱衷鉆研前端技術,對單頁應用開發和前端工程化有著濃厚的興趣。



          在前面

          今年國慶假期終于可以憋在家里了不用出門了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費,睡覺、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風,趕緊起來把文章寫完。

          這篇文章比較基礎,在國慶期間的業余時間寫的,這幾天又完善了下,力求把更多的前端所涉及到的關于文件上傳的各種場景和應用都涵蓋了,若有疏漏和問題還請留言斧正和補充。

          自測讀不讀

          以下是本文所涉及到的知識點,break or continue ?

          • 文件上傳原理
          • 最原始的文件上傳
          • 使用 koa2 作為服務端寫一個文件上傳接口
          • 單文件上傳和上傳進度
          • 多文件上傳和上傳進度
          • 拖拽上傳
          • 剪貼板上傳
          • 大文件上傳之分片上傳
          • 大文件上傳之斷點續傳
          • node 端文件上傳

          原理概述

          原理很簡單,就是根據 http 協議的規范和定義,完成請求消息體的封裝和消息體的解析,然后將二進制內容保存到文件。

          我們都知道如果要上傳一個文件,需要把 form 標簽的enctype設置為multipart/form-data,同時method必須為post方法。

          那么multipart/form-data表示什么呢?

          multipart互聯網上的混合資源,就是資源由多種元素組成,form-data表示可以使用HTML Forms 和 POST 方法上傳文件,具體的定義可以參考RFC 7578。

          multipart/form-data 結構

          看下 http 請求的消息體



          • 請求頭:

          Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次請求要上傳文件,其中boundary表示分隔符,如果要上傳多個表單項,就要使用boundary分割,每個表單項由———XXX開始,以———XXX結尾。

          • 消息體- Form Data 部分

          每一個表單項又由Content-Type和Content-Disposition組成。

          Content-Disposition: form-data 為固定值,表示一個表單元素,name 表示表單元素的 名稱,回車換行后面就是name的值,如果是上傳文件就是文件的二進制內容。

          Content-Type:表示當前的內容的 MIME 類型,是圖片還是文本還是二進制數據。

          解析

          客戶端發送請求到服務器后,服務器會收到請求的消息體,然后對消息體進行解析,解析出哪是普通表單哪些是附件。

          可能大家馬上能想到通過正則或者字符串處理分割出內容,不過這樣是行不通的,二進制buffer轉化為string,對字符串進行截取后,其索引和字符串是不一致的,所以結果就不會正確,除非上傳的就是字符串。

          不過一般情況下不需要自行解析,目前已經有很成熟的三方庫可以使用。

          至于如何解析,這個也會占用很大篇幅,后面的文章在詳細說。

          最原始的文件上傳

          使用 form 表單上傳文件

          在 ie時代,如果實現一個無刷新的文件上傳那可是費老勁了,大部分都是用 iframe 來實現局部刷新或者使用 flash 插件來搞定,在那個時代 ie 就是最好用的瀏覽器(別無選擇)。

          DEMO



          這種方式上傳文件,不需要 js ,而且沒有兼容問題,所有瀏覽器都支持,就是體驗很差,導致頁面刷新,頁面其他數據丟失。

          HTML

           <form method="post" action="http://localhost:8100" enctype="multipart/form-data">
          
                  選擇文件:
                      <input type="file" name="f1"/> input 必須設置 name 屬性,否則數據無法發送<br/>
          <br/>
                      標題:<input type="text" name="title"/><br/><br/><br/>
          
                  <button type="submit" id="btn-0">上 傳</button>
          
          </form>
          
          復制代碼

          文件上傳接口

          服務端文件的保存基于現有的庫koa-body結合 koa2實現服務端文件的保存和數據的返回。

          在項目開發中,文件上傳本身和業務無關,代碼基本上都可通用。

          在這里我們使用koa-body庫來實現解析和文件的保存。

          koa-body 會自動保存文件到系統臨時目錄下,也可以指定保存的文件路徑。



          然后在后續中間件內得到已保存的文件的信息,再做二次處理。

          • ctx.request.files.f1 得到文件信息,f1為input file 標簽的 name
          • 獲得文件的擴展名,重命名文件

          NODE

          /**
           * 服務入口
           */
          var http = require('http');
          var koaStatic = require('koa-static');
          var path = require('path');
          var koaBody = require('koa-body');//文件保存庫
          var fs = require('fs');
          var Koa = require('koa2');
          
          var app = new Koa();
          var port = process.env.PORT || '8100';
          
          var uploadHost= `http://localhost:${port}/uploads/`;
          
          app.use(koaBody({
              formidable: {
                  //設置文件的默認保存目錄,不設置則保存在系統臨時目錄下  os
                  uploadDir: path.resolve(__dirname, '../static/uploads')
              },
              multipart: true // 開啟文件上傳,默認是關閉
          }));
          
          //開啟靜態文件訪問
          app.use(koaStatic(
              path.resolve(__dirname, '../static') 
          ));
          
          //文件二次處理,修改名稱
          app.use((ctx) => {
              var file = ctx.request.files.f1;//得道文件對象
              var path = file.path;
              var fname = file.name;//原文件名稱
              var nextPath = path+fname;
              if(file.size>0 && path){
                  //得到擴展名
                  var extArr = fname.split('.');
                  var ext = extArr[extArr.length-1];
                  var nextPath = path+'.'+ext;
                  //重命名文件
                  fs.renameSync(path, nextPath);
              }
              //以 json 形式輸出上傳文件地址
              ctx.body = `{
                  "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
              }`;
          });
          
          /**
           * http server
           */
          var server = http.createServer(app.callback());
          server.listen(port);
          console.log('demo1 server start ......   ');
          復制代碼

          CODE

          https://github.com/Bigerfe/fe-learn-code/

          果我們測試一個版本時遇到Bug,然后等開發改了以后及時驗證,開發可能會好心提醒一句,你先清一下瀏覽器緩存再測,是不是經常碰到這種情況?所以我們在測試中要經常和緩存打交道,既然是老朋友了,那我們干脆來好好認識一下它。

          緩存基本上是對網頁上經常訪問的資源的存儲和重用。由于存儲是在快速訪問的地方完成的,因此導航速度更快,這也提高了網站和應用程序的性能。這就是為什么 HTTP 緩存對于想要優化用戶體驗并因此增加收入的企業來說是必不可少的工具。

          每一毫秒都很重要

          如果你被問到一個網站最讓你煩惱的是什么,你可能會回答說這是一個網站加載速度很慢。而且有調查顯示:70%的消費者表示,網頁加載的速度會直接影響他們在線購買的意愿。網頁的緩慢加載和呈現會影響用戶體驗,從而導致失去客戶參與和銷售的機會。

          由于我們生活在即時性的時代,因此在虛擬世界中逃脫的任何事物都是失敗的代名詞。百度和其他搜索引擎在對搜索進行排名時不會推薦緩慢的網站,想象一下用戶在等待查看和瀏覽網站時的體驗和時間消耗。

          在訪問量大的時候,使網站更快的有效方法是使用緩存。你應該聽說過緩存,至于它是什么,以及如何工作的,這就是接下來要談的內容。

          什么是 HTTP 緩存?

          為了更好地理解什么是HTTP緩存,首先你得知道HTTP是什么。簡而言之HTTP是一種基于文本的應用層傳輸協議,我們一般稱之為“超文本傳輸協議”,基于該協議可以傳輸如圖像、圖形、URL、 HTML 文本和腳本之類,那么這些的存儲和重用,那這樣留下備份就被稱為緩存,從而防止每次訪問頁面時都下載它們。緩存的主要目的是通過重用以前的響應消息來滿足當前的請求來提高通信性能。

          HTTP 緩存是如何工作的?

          緩存的工作方式如下:


          1. 網站頁面向源服務器請求資源。
          2. 系統檢查緩存以查看是否已存儲資源的副本。
          3. 如果資源已緩存,那么資源將從緩存中傳送。
          4. 如果未緩存資源,則會導致緩存丟失,并且文件將在其源服務器中訪問。
          5. 緩存資源后,會一直優先使用該資源,直到過期或清除緩存。

          緩存的類型

          緩存的類型是根據內容的存儲位置定義的。

          • 瀏覽器緩存 -也叫客戶端緩存, 是指存儲在客戶端中的緩存,一般提到緩存我們首先想到的就是此類。所有瀏覽器都有一個本地存儲,通常用于檢索以前訪問的資源。這種類型的緩存是私有的,因為存儲的資源不共享。客戶端緩存可以存儲網頁的靜態資源,例如CSS、JavaScript、圖片等,以及一些動態內容,例如AJAX請求的響應。
          • 反向代理服務器緩存 - 也稱為網關緩存,它是一個單獨的獨立層,此存儲位于客戶端和應用程序之間。它緩存客戶端發出的請求并將其發送到應用程序,并對從應用程序發送到客戶端的響應執行相同的操作。如果再次請求資源,緩存會在到達應用程序之前返回響應。它也是一個共享緩存,但由服務器而不是用戶共享。
          • 代理服務器緩存 - 此存儲(也稱為中間緩存)在客戶端和源服務器之間的代理服務器上完成。這是一種共享緩存,因為它由多個客戶端使用,通常由提供程序維護。
          • 應用程序緩存 - 此存儲是在應用程序中完成的。它允許開發人員指定瀏覽器應該緩存哪些文件,并使用戶即使在離線時也可以使用它們。
          • CDN緩存 -CDN緩存是一種分布式緩存技術,通過將數據緩存在全球各地的CDN節點上,加速內容的傳輸和訪問。CDN緩存通常用于存儲靜態資源,例如圖片、視頻、音頻等,以減少數據傳輸的延遲和帶寬消耗。

          緩存頭

          在緩存頭中,給出了用于定義緩存特征的指令。例如:


          緩存控制

          在緩存頭中,可以為緩存提供以下標準指令:

          • private

          內容被視為私有內容,因為只有一個用戶有權訪問。在這種情況下,私有內容可以由客戶端的瀏覽器存儲,但不能由中間緩存存儲。

          • public

          內容被視為公開內容,因為多個用戶可以訪問。內容可以由瀏覽器存儲,也可以存儲在客戶端和服務器之間的其他緩存中。

          • max-age

          定義在不在源服務器上重新驗證的情況下可以緩存內容的最長時間。時間以秒為單位定義,最大值為一年(31,536,000 秒)。

          • no-store

          無法緩存內容,因此請求始終發送到源服務器。傳輸機密數據時會標明此格式。

          • no-cache

          必須在每個新請求中重新驗證緩存的內容,這會使內容立即過時。在這種情況下,緩存會在釋放存儲的副本之前將請求發送到源服務器進行驗證。

          • s-maxage

          指示可以緩存內容的時間量,因此與 max-age 非常相似,但不同之處在于此選項僅適用于中間緩存,而不適用于瀏覽器。

          • expires

          Expires 標頭定義內容何時過期。在指定的時間之后,緩存的內容將被視為過時,因此請求將有權訪問源服務器上的最新內容。

          • etag

          Etag(實體標簽)標頭用于驗證瀏覽器的緩存資源是否與源服務器上的緩存資源相同。也就是說,它驗證客戶端是否正在接收緩存內容的最新版本。此標頭用作與網站上每個資源關聯的唯一標識符。為了進行標識,網頁服務器使用 Etag 值,該值在每次更改資源時都會修改。ETag 值是上次更新資源的日期和時間。

          • last-modified

          Last-Modified 標頭顯示瀏覽器上次修改資源的時間,以及它是否應使用緩存的副本或下載最新版本。例如,當用戶訪問您的網站時,瀏覽器會存儲頁面的資源,因此當他們下次訪問該網站時,服務器會檢查文件自上次訪問以來是否已更改。如果沒有修改,服務器會向瀏覽器發送“304 not modified”響應,并使用緩存的副本。

          • vary

          Vary 標頭可以存儲相同內容的不同版本,因此它用于請求緩存以在決定請求哪些內容之前檢查其他標頭。例如,當與 Accept-Encoding 標頭一起使用時,該設置允許區分壓縮和未壓縮的內容,或者當與User-Agent 標頭一起使用時,它會區分移動或桌面網站的版本。

          緩存的好處

          • 減少延遲提升網頁加載速度
          • 減少帶寬消耗;
          • 減少網絡流量;
          • 支持網頁離線瀏覽;
          • 網站速度和性能提高。


          測試人員在什么場景下要留意緩存

          1.及時驗證測試

          這是最常見的一類需要注意緩存的情況,就是如果遇到一些小bug,需要開發立即改好后驗證,那就可以等開發改完,測試這邊需要把驗證用到的瀏覽器緩存清除一次,因為很可能頁面還用的之前的緩存數據;

          2. 頁面加載性能測試

          緩存可以用于加速頁面加載時間。測試人員需要驗證頁面加載性能,并確保緩存策略不會導致頁面內容過時或不一致;

          3. 數據一致性測試

          當應用程序使用緩存來存儲數據時,測試人員需要測試緩存對數據一致性的影響。驗證數據在緩存和數據庫之間的同步性,以及在數據更新時緩存的更新機制,這點也是很重要的;

          4. 用戶認證和授權測試

          緩存可能包含用戶的認證和授權信息。測試人員需要驗證用戶登錄和注銷時緩存的正確更新,以及對用戶權限變更的處理,雖然這在登錄模塊中是比較次要的測試,但是對于安全性要求較高的系統還是比較重要的;

          5. 并發性能測試

          在高并發環境下,緩存的并發讀寫可能導致性能問題。測試人員需要驗證緩存在高負載情況下的表現,確保它能夠正確處理并發請求,這對于性能有要求的系統就極為重視。


          總結

          總之,HTTP緩存是Web性能優化的關鍵組成部分,也是測試工程師所要牢牢掌握的知識點,理解了http緩存有助于我們對web的架構有更深的認識,這樣才能在測試中駕輕就熟。


          主站蜘蛛池模板: 国产精品高清一区二区三区不卡| 日韩精品免费一区二区三区| 国产一区二区三区露脸| 国产精品女同一区二区久久 | 久久久久国产一区二区三区| 无码AV天堂一区二区三区| 在线|一区二区三区四区| 国产激情无码一区二区| 福利一区二区三区视频午夜观看| 日本一区二区不卡视频| 国产人妖视频一区在线观看| 男女久久久国产一区二区三区| 国产在线精品一区二区在线看| 夜夜添无码试看一区二区三区| 亚洲熟女乱色一区二区三区| 一区二区乱子伦在线播放| 国产AV天堂无码一区二区三区| 天堂Aⅴ无码一区二区三区| 日本精品高清一区二区2021| 一区二区在线免费观看| 久久国产三级无码一区二区| 免费看无码自慰一区二区| 亚拍精品一区二区三区| 亚洲综合无码AV一区二区| 国产综合精品一区二区| 亚洲一区二区三区播放在线| 日本一区午夜艳熟免费| 亚洲AⅤ无码一区二区三区在线 | 亚洲中文字幕无码一区二区三区| 精品国产AV一区二区三区| 亚洲国产国产综合一区首页| 国产福利电影一区二区三区,亚洲国模精品一区 | 色欲综合一区二区三区| 无码精品人妻一区| 国产精品一区二区毛卡片| 亚洲午夜精品一区二区公牛电影院| 国产精品亚洲专一区二区三区| 日韩人妻无码一区二区三区99| 中文字幕在线播放一区| 国产福利电影一区二区三区,日韩伦理电影在线福 | 国产天堂在线一区二区三区|