http缓存的实现方式有html
1.Cache-Control/Expires。Cache-Control的Max-age属性设置的绝对过时时间,单位为秒。好比max-age:300,表示文件会缓存在本地300s以后过时.Expires表明的是绝对缓存时间,表示缓存在指定的时间点过时,格式为Expires:Thu,20 Apr 2019 20:00:00 GMT。这个时间是由服务器设置的,但本地浏览器和服务器之间可能存在时差,因此有时这个值不许确。当Cache-Control的max-age和expires同时存在时,max-age的优先级高。node
2.Last-Modify/If-Modify-Since。这两个是成对存在的,表明文件最后的修改时间, Last-Modified 是由服务器往浏览器发送的 HTTP头,每次发送的值会写进浏览器的If-Modify-Since中。If-Modified-Since是由浏览器往服务器发送的头,浏览器每次请求服务器都会带上这个头。git
3.Etag/If-None-Match.这也是成对存在,功能和(2)相似。不过在开发中每每是对服务器的文件求Hash,并把求出的hash值赋给Etag。当Etag和Last-Modify同时存在的时候服务端对两种都要校验。github
4.Etag和Last-Modify对比。
(a)、服务器周期性动态生成的文件,他的内容并不改变,但修改时间变了这时咱们应该用Etag (b)、对于修改很是频繁的文件,Etag能够检测到秒级如下,If-Modified-Since只能能检查到s级的。浏览器
5.Last-Modified,Etag,Expire 混合使用
(a)、一般 Last-Modified,Etag,Expire 是一块儿混合使用的,特别是 Last-Modified 和 Expire 常常一块儿使用,由于 Expire 可让浏览器彻底不发起 Http 请求,而当浏览器强制 F5 的时候又有 Last-Modified ,这样就很好的达到了浏览器段缓存的效果。
(b)、Etag 和 Expire 一块儿使用时,先判断 Expire ,若是已通过期,再发起 Http 请求,若是 Etag 也过时,则返回 200 响应。若是 Etag 没有过时则返回 304 响应。
(c)、Last-Modified,Etag,Expires 三个同时使用时。先判断 Expire ,而后发送 Http 请求,服务器先判断 last-modified ,再判断 Etag ,必须都没有过时,才能返回 304 响应缓存
上面说了那么一大堆,如今用node来实现一个Last-Modify/If-Modify-Since的缓存bash
const http = require('http');
const fs = require('fs');
const urlLib = require('url');
http.createServer((req, res) => {
let { pathname } = urlLib.parse(req.url, true);
if (pathname != '/index.html') {
res.writeHead(302, { 'Location': 'http://localhost:9090/index.html' });
res.end();
} else {
let rs = fs.createReadStream(`./${pathname}`);
rs.pipe(res);
}
}).listen(9090);
console.log('server start at http://localhost:9090/index.html')
复制代码
http.createServer((req, res) => {
let { pathname } = urlLib.parse(req.url, true);
if (pathname != '/index.html') {
res.writeHead(302, { 'Location': 'http://localhost:9090/index.html' });
res.end();
} else {
+ fs.stat(`./${pathname}`, (err, stat) => {
if (err) {
console.log('请在根目录下建立一个index.html文件');
} else {
+ if (req.headers['if-modified-since']) {
+ console.log(req.headers['if-modified-since'])
}
+ res.setHeader('Last-Modified', stat.mtime.toGMTString());
let rs = fs.createReadStream(`./${pathname}`);
rs.pipe(res);
}
})
}
}).listen(9090);
复制代码
fs.stat(`./${pathname}`, (err, stat) => {
if (err) {
console.log('请在根目录下建立一个index.html文件');
} else {
if (req.headers['if-modified-since']) {
+ let date = new Date(req.headers['if-modified-since']);
+ let client_time = Math.floor(date.getTime() / 1000);
+ let server_time = Math.floor(stat.mtime.getTime() / 1000);
+ if (client_time < server_time) {
+ sentFileToClient();
+ } else {
+ res.writeHead(304);
+ res.write('Not Modified');
+ res.end();
}
} else {
sentFileToClient();
}
function sentFileToClient() {
res.setHeader('Last-Modified', stat.mtime.toGMTString());
let rs = fs.createReadStream(`./${pathname}`);
rs.pipe(res);
}
}
})
复制代码