node.js實(shí)現(xiàn)http服務(wù)器與瀏覽器之間的內(nèi)容緩存操作示例
本文實(shí)例講述了node.js實(shí)現(xiàn)http服務(wù)器與瀏覽器之間的內(nèi)容緩存操作。分享給大家供大家參考,具體如下:
一、緩存的作用
1、減少了數(shù)據(jù)傳輸,節(jié)約流量。
2、減少服務(wù)器壓力,提高服務(wù)器性能。
3、加快客戶端加載頁(yè)面的速度。
二、緩存的分類
1、強(qiáng)制緩存,如果緩存有效,則不需要與服務(wù)器發(fā)生交互,直接使用緩存。
2、對(duì)比緩存,每次都需要與服務(wù)器發(fā)生交互,對(duì)緩存進(jìn)行比較判斷是否可以使用緩存。
三、通過(guò)使用 Last-Modified / If-Modified-Since 來(lái)進(jìn)行緩存判斷
1、Last-Modified 是服務(wù)器向客戶端發(fā)送的頭信息,用于告訴客戶端資源的 最后修改時(shí)間,該信息瀏覽器會(huì)保存起來(lái)。
2、If-Modified-Since 是客戶端向服務(wù)器發(fā)送的頭信息,當(dāng)客戶端再次請(qǐng)求資源時(shí),瀏覽器會(huì)帶上該信息發(fā)送給服務(wù)器,服務(wù)器通過(guò)該信息來(lái)判斷資源是否過(guò)期。
3、如果沒(méi)有過(guò)期,則響應(yīng) 304 表示 未更新,告訴瀏覽器使用保存的緩存。
4、如果過(guò)期了,則響應(yīng) 200,返回最新的資源。
const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const util = require('util'); const mime = require('mime'); //創(chuàng)建http服務(wù)器并監(jiān)聽端口 let server = http.createServer(); server.listen(1234, '0.0.0.0', function () { console.log('開始監(jiān)聽'); }); function sendFile(req, res, filePath, stats) { //設(shè)置文件內(nèi)容類型 res.setHeader('Content-Type', mime.getType(filePath)); //設(shè)置資源最后修改時(shí)間頭信息 res.setHeader('Last-Modified', stats.ctime.toGMTString()); //通過(guò)管道將文件數(shù)據(jù)發(fā)送給客戶端 fs.createReadStream(filePath).pipe(res); } server.on('request', function (req, res) { let {pathname} = url.parse(req.url, true); //獲取文件真實(shí)路徑 let filePath = path.join(__dirname, pathname); //判斷文件是否存在 fs.stat(filePath, function (err, stats) { if (err) { return res.end(util.inspect(err)); } if (!stats.isFile()) { return res.end('is not file'); } //獲取客戶端請(qǐng)求的If-Modified-Since頭信息 let ifModifiedSince = req.headers['if-modified-since']; if (ifModifiedSince) { //如果最后修改時(shí)間相同,說(shuō)明該資源并未修改,直接響應(yīng) 304,讓瀏覽器從緩存中獲取數(shù)據(jù)。 if (ifModifiedSince == stats.ctime.toGMTString()) { res.statusCode = 304; res.end(); } else { sendFile(req, res, filePath, stats); } } else { sendFile(req, res, filePath, stats); } }); });
通過(guò)最后修改時(shí)間判斷緩存是否可用,并不是很精確,有如下幾個(gè)問(wèn)題:
1、Last-Modified 只精確到秒,秒以下的時(shí)間修改,將無(wú)法準(zhǔn)確判斷。
2、文件最后修改時(shí)間變了,但 內(nèi)容并沒(méi)有發(fā)生改變。
3、文件存在于多個(gè) CDN 上,那該文件的最后修改時(shí)間是不一樣的。
四、通過(guò) ETag / If-None-Match 進(jìn)行判斷
ETag 表示 實(shí)體標(biāo)簽,將內(nèi)容通過(guò) hash 算法生成一段字符串,用以標(biāo)識(shí)資源,如果資源發(fā)生變化,則 ETag 也會(huì)變化。
ETag 是服務(wù)器生成的,發(fā)送給客戶端的。
1、客戶端請(qǐng)求資源,服務(wù)器根據(jù)資源生成ETag,發(fā)送給客戶端。瀏覽器會(huì)保存該信息。
2、當(dāng)客戶端再次請(qǐng)求時(shí),瀏覽器會(huì)發(fā)送 If-None-Match 給服務(wù)器,值為第1步保存的信息,服務(wù)器通過(guò)該信息進(jìn)行判斷,資源是否修改過(guò)。
3、如果沒(méi)有修改過(guò),則響應(yīng) 304 未更新,告訴瀏覽器使用保存的緩存。
4、如果修改過(guò),則響應(yīng) 200,返回最新資源。
const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const util = require('util'); const crypto = require('crypto'); const mime = require('mime'); //創(chuàng)建http服務(wù)器并監(jiān)聽端口 let server = http.createServer(); server.listen(1234, '0.0.0.0', function () { console.log('開始監(jiān)聽'); }); function sendFile(req, res, filePath, eTag) { //設(shè)置文件內(nèi)容類型 res.setHeader('Content-Type', mime.getType(filePath)); //設(shè)置ETag頭信息 res.setHeader('ETag', eTag); //通過(guò)管道將文件數(shù)據(jù)發(fā)送給客戶端 fs.createReadStream(filePath).pipe(res); } server.on('request', function (req, res) { let {pathname} = url.parse(req.url, true); //獲取文件真實(shí)路徑 let filePath = path.join(__dirname, pathname); //判斷文件是否存在 fs.stat(filePath, function (err, stats) { if (err) { return res.end(util.inspect(err)); } if (!stats.isFile()) { return res.end('is not file'); } //獲取客戶端請(qǐng)求的If-None-Match頭信息 let ifNoneMatch = req.headers['if-none-match']; //創(chuàng)建可讀流 let rs = fs.createReadStream(filePath); //創(chuàng)建md5算法 let md5 = crypto.createHash('md5'); rs.on('data', function (data) { md5.update(data); }); rs.on('end', function () { let eTag = md5.digest('hex'); if (ifNoneMatch) { //判斷eTag與客戶端發(fā)送過(guò)來(lái)的If-None-Match是否相等 if (ifNoneMatch == eTag) { res.statusCode = 304; res.end(); } else { sendFile(req, res, filePath, eTag); } } else { sendFile(req, res, filePath, eTag); } }); }); });
五、讓瀏覽器在緩存有效期內(nèi)不用發(fā)請(qǐng)求
Expires 是http1.0的內(nèi)容,用于設(shè)置緩存的有效期,在有效期內(nèi)瀏覽器直接從瀏覽器緩存中獲取數(shù)據(jù)。
Cache-Control 與Expires作用一樣,是http1.1的內(nèi)容,用于指明當(dāng)前資源的有效期,優(yōu)先級(jí)高于Expires。
Cache-Control可以設(shè)置的值 :
1、private 客戶端可以緩存
2、public 客戶端和代理服務(wù)器都可以緩存
3、max-age=10 緩存內(nèi)容在10秒后失效
4、no-cache 使用對(duì)比緩存驗(yàn)證,強(qiáng)制向服務(wù)器驗(yàn)證
5、no-store 內(nèi)容都不緩存,強(qiáng)制緩存和對(duì)比緩存都不會(huì)觸發(fā)
const http = require('http'); const url = require('url'); const path = require('path'); const fs = require('fs'); const util = require('util'); const mime = require('mime'); //創(chuàng)建http服務(wù)器并監(jiān)聽端口 let server = http.createServer(); server.listen(1234, '0.0.0.0', function () { console.log('開始監(jiān)聽'); }); function sendFile(req, res, filePath, stats) { //設(shè)置文件內(nèi)容類型 res.setHeader('Content-Type', mime.getType(filePath)); //設(shè)置緩存失效時(shí)間60秒 res.setHeader('Expires', new Date(Date.now() + 60 * 1000).toUTCString()); //設(shè)置緩存失效時(shí)間60秒 res.setHeader('Cache-Control', 'max-age=60'); //通過(guò)管道將文件數(shù)據(jù)發(fā)送給客戶端 fs.createReadStream(filePath).pipe(res); } server.on('request', function (req, res) { let {pathname} = url.parse(req.url, true); //獲取文件真實(shí)路徑 let filePath = path.join(__dirname, pathname); //判斷文件是否存在 fs.stat(filePath, function (err, stats) { if (err) { return res.end(util.inspect(err)); } if (!stats.isFile()) { return res.end('is not file'); } sendFile(req, res, filePath, stats) }); });
希望本文所述對(duì)大家node.js程序設(shè)計(jì)有所幫助。
相關(guān)文章
nodejs版本過(guò)高導(dǎo)致vue2版本的項(xiàng)目無(wú)法正常啟動(dòng)的解決方案
這篇文章主要給大家介紹了關(guān)于nodejs版本過(guò)高導(dǎo)致vue2版本的項(xiàng)目無(wú)法正常啟動(dòng)的解決方案,本文小編給大家詳細(xì)介紹了如何解決這個(gè)問(wèn)題,如有遇到同樣問(wèn)題的朋友可以參考下2023-11-11詳解Nodejs中自動(dòng)化瀏覽器操作神器Puppeteer的使用
Puppeteer是一個(gè)JavaScript庫(kù),它提供了一種方式來(lái)通過(guò)DevTools協(xié)議控制無(wú)頭瀏覽器,本文主要為大家介紹了Puppeteer的主要特性和使用方法,感興趣的可以了解下2024-01-01node.js中的buffer.Buffer.isBuffer方法使用說(shuō)明
這篇文章主要介紹了node.js中的buffer.Buffer.isBuffer方法使用說(shuō)明,本文介紹了buffer.Buffer.isBuffer的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12淺談node中的exports與module.exports的關(guān)系
本篇文章主要介紹了淺談node中的exports與module.exports的關(guān)系,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Node.js學(xué)習(xí)之內(nèi)置模塊fs用法示例
這篇文章主要介紹了Node.js學(xué)習(xí)之內(nèi)置模塊fs用法,結(jié)合實(shí)例形式詳細(xì)分析了node.js內(nèi)置模塊fs的基本功能、用法與相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2020-01-01windows8.1+iis8.5下安裝node.js開發(fā)環(huán)境
這篇文章主要介紹了windows8.1+iis8.5下安裝node.js開發(fā)環(huán)境的方法,需要的朋友可以參考下2014-12-12node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲練習(xí)
這篇文章主要介紹了node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲練習(xí),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12node.js中使用q.js實(shí)現(xiàn)api的promise化
這篇文章主要介紹了node.js中使用q.js實(shí)現(xiàn)api的promise化,promise一個(gè)標(biāo)準(zhǔn),它描述了異步調(diào)用的返回結(jié)果,包括正確返回結(jié)果和錯(cuò)誤處理,需要的朋友可以參考下2014-09-09