如何利用node實現靜態檔案快取詳解
目錄
- 快取
- 快取位置分類
- 快取設定header
- node實現靜態檔案快取
- 強快取
- 思路
- 程式碼實現
- 效果展示
- 協商快取
- 思路
- 程式碼實現
- 效果展示
- 總結
快取
瀏覽器快取(Brower Caching)是瀏覽器對之前請求過的檔案進行快取,以便下一次訪問時重複使用,節省頻寬,提高訪問速度,降低伺服器壓力
快取位置分類
memory cache:記憶體中的快取,關閉瀏覽器則清空,一般儲存一些庫
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.www.cppcns.com Cache-Control:no-store //每次都請求伺服器,且不快取在瀏覽器中,等同於沒有快取
複製程式碼
Expires:
相容低版本瀏覽器,這個就是設定絕對時間,獲取的是伺服器的當前時間和瀏覽器當前時間做比對(通常存在偏差,是http1.0的產物),和 cache-control同時存在時,cache-control優先順序更高
- last-modified:協商快取的時候用 和If-Modified-Since,成對出現;If-Modified-Since請求頭的值對應上一次伺服器的響應頭last-mowww.cppcns.com
- 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) JZWCUracmG{
// 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,pathname); console.log(req.url); fs.stat(filePath,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靜態檔案快取內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!