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);
}
}
})
複製代碼