如何利用node實現靜態文件緩存詳解
緩存
瀏覽器緩存(Brower Caching)是瀏覽器對之前請求過的文件進行緩存,以便下一次訪問時重復使用,節省帶寬,提高訪問速度,降低服務器壓力
緩存位置分類
memory cache:內存中的緩存,關閉瀏覽器則清空,一般存儲一些js庫
disk cache:硬盤中的緩存,關閉瀏覽器不會馬上清空,一般存儲大文件,比如 圖片資源,iconFont這類的圖標文件庫
兩者的區別:
1. 讀取速度 :memory cache緩存的是當前解析過瞭的文件在瀏覽器tab進程裡,下次運行使用時的可以快速讀取;
disk cache直接將緩存寫入硬盤文件中,讀取緩存需要對該緩存存放的硬盤文件進行I/O(讀取)操作,然後重新解析緩存內容,速度比內存緩存慢
2. 時效性:memory cache是存在tab的進程裡,tab關閉,則清空;
disk cache:被清空的時機我還不知道(希望有人可以補充)
3. 優先級:memory cache大於disk cache
對於大文件來說,大概率是不存儲在memory中的,反之優先,代碼角度目前好像也無法控制瀏覽器緩存位置
緩存設置header
cache-control
1. cache-control:max-age=10//10秒內重新發的請求都直接命中強緩存,無需向服務器發起請求,讀取瀏覽器緩存即可
2. Cache-Control:no-cache //禁止強制緩存,每次都向服務器發起請求,同時也會存在瀏覽器緩存中 (走協商緩存瞭基本)
3. Cache-Control:no-store //每次都請求服務器,且不緩存在瀏覽器中,等同於沒有緩存
復制代碼
Expires:
兼容低版本瀏覽器,這個就是設置絕對時間,獲取的是服務器的當前時間和瀏覽器當前時間做比對(通常存在偏差,是http1.0的產物),和 cache-control同時存在時,cache-control優先級更高
- last-modified:協商緩存的時候用 和If-Modified-Since,成對出現;If-Modified-Since請求頭的值對應上一次服務器的響應頭last-modified的值,擁有提供服務器比對請求資源修改時間,相等,則命中協商緩存返回304,瀏覽器讀取緩存即可
- Etag:資源標識(也有說時指紋,通常是一個md5值),協商緩存時候用,比較文件是否修改;和If-None-Match 成對出現
Etag主要為瞭解決 Last-Modified 無法解決的一些問題。
1. 一些文件也許會周期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個文件被修改瞭,而重新GET;
2. 某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改瞭N次),If-Modified-Since無法檢查到如此精細
3. 某些服務器不能精確的得到文件的最後修改時間;
4.Etag與Last-modify同時存在 Etag優先級比較
實際項目:html不允許緩存,html裡引用的js有唯一的版本號做依據,再次訪問的時候 訪問最新的html,引用的js或其他文件版本號未修改則直接用本地緩存
node實現靜態文件緩存
文件結構
public對應我們測試用的靜態資源
強緩存
思路
- 創建服務
- 首次請求 解析請求路徑, fs.createReadStream().pipe() 讀取文件
- 設置響應頭Cache-Contro:max-age=10 強緩存的相對時間
代碼實現
const http = require("http"); const url = require("url"); const fs = require("fs"); const path = require("path"); // 接收文件路徑 返回該文件對應的文件類型格式 const mime = require("mime");//npm i mime const server = http.createServer((req, res) => { let { pathname, query } = url.parse(req.url, true); //__dirname 當前文件所在的文件夾所處的絕對路徑 和請求路徑拼接 let filePath = path.join(__dirname, "public", pathname); console.log(req.url);//10s內反復刷新頁面,查看是否持續打印,命中強緩存則10s打印一次 // 設置頭部 緩存信息,規定的緩存時間內,客戶端無需再向服務器發起請求 res.setHeader("Cache-Control", "max-age=10"); // 設置緩存時常;請求的當前時間+max-age 的相對時間內,優先級比Expires高 res.setHeader("Expires", new Date(Date.now() + 10).toUTCString()); //兼容低版本瀏覽器,這個就是設置絕對時間,獲取的是服務器的當前時間 // 獲取請求路徑 判斷是文件還是文件目錄 fs.stat(filePath, function (err, statObj) { // url解析錯誤,則請求錯誤 沒有找到對應url資源 返回404 if (err) { res.statusCode = 404; res.end("NOT FOUND"); } else { // 如果是文件,用可讀流+管道 pipe 進行文件內容讀取,利用mime 獲取文件內容格式,並設置編碼規范為utf-8 if (statObj.isFile()) { fs.createReadStream(filePath).pipe(res); res.setHeader( "Content-Type", mime.getType(filePath) + ";charset=utf-8" ); } else { // 如果是文件目錄 找到 目錄下對應的index.html let htmlPath = path.join(filePath, "index.html"); // fs.access判斷拼接的路徑是否可訪問 fs.access(htmlPath, function (err) { if (err) { // 不可訪問 設置 狀態碼404 res.statusCode = 404; res.end("NOT FOUND"); } else { //可訪問,用可讀流加管道 pipe 進行文件內容讀取 fs.createReadStream(htmlPath).pipe(res); res.setHeader("Content-Type", "text/html;charset=utf-8"); } }); } } }); // 寫到這裡 可以 nodemon cache.js 啟動服務 查看 http://localhost:3000/ }); server.listen(3000, () => { console.log("server start 3000"); });
效果展示
協商緩存
成功
思路
- 創建服務
- 首次請求 解析請求路徑, fs.createReadStream().pipe() 讀取文件
- 設置響應頭Last-modified 返回瀏覽器
- 再次請求,比較瀏覽器if-last-modified 和當前資源修改時間,相等則命中協商緩存,返回響應碼304,反之返回路徑對應的最新資源,和響應碼200
代碼實現
const http = require("http"); const url = require("url"); const fs = require("fs"); const path = require("path"); const mime = require("mime"); let filePath = path.join(__dirname, "public", pathname); console.log(req.url); fs.stat(filePath, function (err, statObj) { if (err) { res.statusCode = 404; res.end("NOT FOUND"); } else { if (statObj.isFile()) { // 判斷 瀏覽器請求的文件路徑 的change 時間 通過statObj.ctime const ctime = statObj.ctime.toUTCString(); // 瀏覽器請求頭if-modified-since ===文件上次的修改時間 ,命中協商緩存,則返回 304 瀏覽器緩存中請求資源 if (req.headers["if-modified-since"] === ctime) { res.statusCode = 304; //去瀏覽器緩存中找 res.end(); // } else { // if-modified-since !==文件上次的修改時間,響應頭Last-modified 設置 當前請求文件的 修改時間 做下次 瀏覽器請求的last-modify-since的對應值 res.setHeader("Last-modified", ctime); fs.createReadStream(filePath).pipe(res); res.setHeader( "Content-Type", mime.getType(filePath) + ";charset=utf-8" ); } } else { fs.access(htmlPath, function (err) { if (err) { // 不可訪問 設置 狀態碼404 res.statusCode = 404; res.end("NOT FOUND"); } else { fs.createReadStream(htmlPath).pipe(res); res.setHeader("Content-Type", "text/html;charset=utf-8"); } }); } } }); // 寫到這裡 可以 nodemon cache2.js 啟動服務 查看 http://localhost:3000/ }); server.listen(3000, () => { console.log("server start 3000"); });
效果展示
每次刷新頁面都會執行 console.log(req.url); 請求瞭服務器但服務器返回304 命中協商緩存 瀏覽器直接讀取緩存資源即可
成功
總結
到此這篇關於如何利用node實現靜態文件緩存的文章就介紹到這瞭,更多相關node靜態文件緩存內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!