查看 http-server
源码
http-server\lib\core\index.js
stat {
ino 索引节点号
mtime:最后一次修改文件的时间
size 以字节为单位的文件容量
}
function statFile() {
// stat 检查文件是否存在
fs.stat(file, (err, stat) => {
// 求 为文件生成 lastModified etag
const lastModified = (new Date(stat.mtime)).toUTCString();
const etag = generateEtag(stat, weakEtags);
// response 返回给浏览器
res.setHeader('last-modified', lastModified);
res.setHeader('etag', etag);
if (shouldReturn304(req, lastModified, etag)) {
status[304](res, next);
return;
}
})
}
第一次请求头 没有 If-Modified-Since
和 If-None-Match
第二次请求头
多提交了 If-Modified-Since
和 If-None-Match
If-None-Match
上次传返回的 etag
If-Modified-Since
上次传返回的 last-modified
根据 stat
生成etag,可以看到 etag 中包含了上传修改时间
第二次请求,lastModified 和 etag 全相等,则返回 304 ,使用协商缓存
1.先 lastModified 和服务器的 serverLastModified比较,如果服务器的 时间大于 提交的时间则不使用协商缓存,表明文件有更新。一般没更新获取到的都是是相等的
// 不是东八区时间,而是国际标准时区
// 东八区格式:Wed Dec 13 2023 17:52:31 GMT+0800
new Date(Date.parse('Wed, 13 Dec 2023 06:15:31 GMT'))
2.检查 eatg 是否相等
function shouldReturn304(req, serverLastModified, serverEtag) {
if (!req || !req.headers) {
return false;
}
const clientModifiedSince = req.headers['if-modified-since'];
const clientEtag = req.headers['if-none-match'];
let clientModifiedDate;
if (!clientModifiedSince && !clientEtag) {
// Client did not provide any conditional caching headers
return false;
}
if (clientModifiedSince) {
// Catch "illegal access" dates that will crash v8
try {
clientModifiedDate = new Date(Date.parse(clientModifiedSince));
} catch (err) {
return false;
}
if (clientModifiedDate.toString() === 'Invalid Date') {
return false;
}
// If the client's copy is older than the server's, don't return 304
if (clientModifiedDate < new Date(serverLastModified)) {
return false;
}
}
if (clientEtag) {
// Do a strong or weak etag comparison based on setting
// https://www.ietf.org/rfc/rfc2616.txt Section 13.3.3
if (opts.weakCompare && clientEtag !== serverEtag
&& clientEtag !== `W/${serverEtag}` && `W/${clientEtag}` !== serverEtag) {
return false;
}
if (!opts.weakCompare && (clientEtag !== serverEtag || clientEtag.indexOf('W/') === 0)) {
return false;
}
}
return true;
}
强制不使用协商缓存,本质都是浏览器不发送 If-Modified-Since
和 If-None-Match
字段
ctrl + F5
- 禁用缓存
参考文献:
https://nodejs.cn/api/fs.html#fsstatpath-options-callback
https://github.com/http-party/http-server
https://juejin.cn/post/6974529351270268958
https://blog.csdn.net/u012294618/article/details/72630092