自动化缓存策略-处理大规模缓存的方案
http-Header(协议头部):基于http-Request(请求头部)和http-Response(响应头)来实现的缓存策略
缓存策略(一)cache-control
属性:
max-age:
指定缓存的有效时间
s-maxage:
只能指定Public类型的缓存,优先级高于max-age
private:
私有缓存,如果个人计算机上的缓存
public:
公开缓存,如cdn服务器上的资源缓存,因为共很多用户使用所以是public
no-cache:
请求获取当前服务器端该文件的Last-Modified
对比判断是否使用继续使用
本地缓存文件
no-store:完全不使用缓存
expires:指定资源到期时间,指服务端具体时间点,过期之前均从浏览器缓存读取数据
从serviceWorker中读取资源
从内存中读取缓存资源
从硬盘中读取缓存资源
缓存策略(二)客户端和服务端缓存协商
方案一
服务器响应头Last-modified
和请求头if-modified-since
(请求头发送上次获得的该文件最后更新时间如果服务端上该文件最后修改时间发生了变化,那么返回状态码是200:请求成功,如果该文件最后修改时间没变,则返回304)
注意:
last-modified缺点:
1、某些服务端不能获取精确修改时间
2、修改时间变化但是文件内容并没有变
3、以秒为单位的判断间隔不精确
方案二
弥补以上不足的方案:Etag/If-None-Match
特点:
通过当前文件内容的hash值进行判断,如果没有变化则返回304如果服务端文件有变化则200
优点:
通过文件内容的hash进行判断是否变更,非常精确
分级缓存策略
1、200状态(from cache)
由expires/cache-control控制,其中expires(http1.0有效)是绝对时间
cache-control:max-age,s-maxage(http1.1)相对时间,两者都存在时cache-control优先级高,只要缓存没过期,部分缓存资源浏览器访问自己的缓存资源读取
2、304状态
这一层由last-modified/etag控制,当第1步
失效或用户点击刷新或者按F5时,浏览器就会发送请求给服务器,如果服务器没有变化则返回304
,如果发现了变化拉去最新资源返回200
3、200
当浏览器没有缓存或者第2步
失效或者用户选择ctrl+f5时,浏览器直接拉取数据
示意图
首次加载
非首次加载
缓存实战:
- 1、新建文件config.js
- 2、新建文件mime.js
- 3、新建文件service.js
- 4、新建文件夹并放入模拟请求的静态资源
config:
exports.Expires = {
fileMatch: /^(gif|png|jpg|js|css)$/ig, //指定缓存文件类型
maxAge: 60 * 60 * 24 * 365 //过期时间
}
mime:
exports.types={
"jpg":"image/jpeg",
"json":"application/json"
} //设置contentType
service:
let http = require("http")
let url = require("url")
let fs = require("fs")
let path = require("path")
let mime = require("./mime").types
let expiresConfig = require("./config") //缓存配置
let port = 9000;
let server = http.createServer((request, response) => {
let pathname = url.parse(request.url).pathname
let realPath = "assets" + pathname
let ext = path.extname(realPath) //获取请求文件扩展名
ext = ext ? ext.slice(1) : "unknown" //判断是否存在扩展名
if (ext.match(expiresConfig.Expires.fileMatch)) { //匹配到指定缓存文件类型
let expires = new Date();
expires.setTime(expires.getTime() + expiresConfig.Expires.maxAge * 1000) //设置过期时间
response.setHeader("Expires", expires.toUTCString())
response.setHeader("Cache-Control", "max-age=" + expiresConfig.Expires.maxAge)
}
//启用last-modified 304
fs.stat(realPath, function (err, stat) {
let lastModified = stat.mtime.toUTCString(); //获取文件最后修改时间
response.setHeader("Last-Modified", lastModified)
let contentType = mime[ext] || "text/plain";
//对比文件最后修改时间如果没有修改,则使用浏览器缓存文件,此时状态码:304
if (request.headers["if-modified-since"] && lastModified == request.headers["if-modified-since"]) {
response.writeHead(304, "Not Modified")
response.end()
} else {
//请求文件的最后修改时间发生变化,则读取最新文件,此时请求成功状态码:200
fs.exists(realPath, (exists) => {
if (!exists) {
response.writeHead(404, {
"Content-Type": "text/plain"
})
response.write('this request URL ' + pathname + ' was not fined')
response.end()
} else {
fs.readFile(realPath, "binary", function (err, file) {
if (err) {
response.writeHead(500, {
"Content-Type": "text/plain"
})
} else {
response.writeHead(200, {
"Content-Type": contentType
})
response.write(file, "banary")
response.end()
}
})
}
})
}
})
})
server.listen(port)
console.log("server runing at port:", port)
过期时间示意图
304请求资源版本校验
使用本地缓存资源时的请求消耗资源大小
欢迎加微信一起学习:13671593005
未完待续…gzip的使用…