响应头中设置 Expires的值为格林威治时间 就是告诉客户端,此资源的请求可以用到指定时间点,在此时间之前,都要重新发请求到服务器请求这个资源,强制读取缓存
服务器时间可能和客户端时间不同,所以这种缓存策略不是特别靠谱
res.setHeader('Expires', new Date(Date.now()+10000).toUTCString())
响应头中设置 cache-control max-age=10 时间单位为s,意思告诉客户端,此次缓存有效期为10秒,次中策略,要配合last-modified,只在1.1中有效,优先级大于expires
res.setHeader('Cache-Control','max-age=20')
协商缓存
这是一组通过协商修改时间为基础的策略 客户端==========》初次发起请求inde.js===================》服务器端 客户端《=====应答last-modified : 时间点(格林威治时间)《======服务器端 客户端==》二次请求index.js if-mofied-since:时间点(格林威治时间)==》服务器端 客户端《============过期应答200 index.js《================服务器端 客户端《==========未过期应答304 index.js《================服务器端 大概意思是,每次都会请求到服务,由服务器根据客户端发来的if-mofied-since(就是首次请求服务器相应的last-modified时间)时间,判断这个时间是判断是否协商缓存命中,如果缓存命中,服务器返回状态码304,内容为空即可,否则返回200,内容为最新的资源
res.setHeader('Cache','no-cache')
res.setHeader('last-modified',new Date().toUTCString())
if(new Date(req.headers['if-modified-since']).getTime()+10000>Date.now()){
console.log('协商缓存命中')
res.statusCode=304;
res.end()
return
}
另一种协商缓存是根据内容判断,一般做法是将返回内容进行摘要(hash),然后通过对比摘要来判断内容是否更新 客户端==========》初次发起请求inde.js===================》服务器端 客户端《============应答Etag : 时间内容hash《=============服务器端 客户端====》二次请求index.js if-None-Match================》服务器端 客户端《============过期应答200 index.js《================服务器端 客户端《==========未过期应答304 index.js《================服务器端 内容不改一直缓存命中,只有内容改变,才会重新给资源
function updateTime() {
this.timer=this.timer||setInterval(() => this.time = new Date().toUTCString(), 7000)
return this.time;
}
const http = require('http')
const serve = http.createServer((req, res) => {
const { url } = req;
if (url === '/') {
res.end(`
<html>
HTML update Time ${updateTime()}
<script src="main.js"></script>
</html>
`)
} else if (url === '/main.js') {
const content = `document.writeln('<br>JS updateTime :${updateTime()}')`
// res.setHeader('Expires', new Date(Date.now()+10000).toUTCString())
// res.setHeader('Cache-Control','max-age=20')
res.setHeader('Cache','no-cache')
// res.setHeader('last-modified',new Date().toUTCString())
// if(new Date(req.headers['if-modified-since']).getTime()+10000>Date.now()){
// console.log('协商缓存命中')
// res.statusCode=304;
// res.end()
// return
// }
// hash算法库
const crypto = require('crypto')
// sha1模式获取content的二进制hash转为16进制的hash
const hash = crypto.createHash('sha1').update(content).digest('hex')
res.setHeader('Etag', hash)
if (req.headers['if-none-match'] === hash) {
console.log('协商缓存命中')
res.statusCode = 304;
res.end();
return
}
res.statusCode = 200
res.end(content)
} else if (url === '/favicon.ico') {
res.end('')
}
});
serve.listen(4000, () => {
console.log('服务启动在http://localhost:4000')
})