数据传输,节省了网费。性能速度



最后修改时间If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向服务器请求时带上头If-Modified-Since。响应最新的资源内容并返回200状态码;未更新,告知浏览器继续使用所保存的缓存文件。let http = require('http');
let fs = require('fs');
let path = require('path');
let mime = require('mime');
http.createServer(function (req, res) {
    let file = path.join(__dirname, req.url);
    fs.stat(file, (err, stat) => {
        if (err) {
            sendError(err, req, res, file, stat);
        } else {
            let ifModifiedSince = req.headers['if-modified-since'];
            if (ifModifiedSince) {
                if (ifModifiedSince == stat.ctime.toGMTString()) {
                    res.writeHead(304);
                    res.end();
                } else {
                    send(req, res, file, stat);
                }
            } else {
                send(req, res, file, stat);
            }
        }
    });
}).listen(8080);
function send(req, res, file, stat) {
    res.setHeader('Last-Modified', stat.ctime.toGMTString());
    res.writeHead(200, { 'Content-Type': mime.getType(file) });
    fs.createReadStream(file).pipe(res);
}
function sendError(err, req, res, file, stat) {
    res.writeHead(400, { "Content-Type": 'text/html' });
    res.end(err ? err.toString() : "Not Found");
}
最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。精确到秒。内容并未改变。 我们不希望客户端认为这个文件修改了。CDN服务器上的时候内容虽然一样,修改时间不一样。ETag是实体标签的缩写,根据实体内容生成的一段hash字符串,可以标识资源的状态。当资源发生改变时,ETag也随之发生变化。
ETag是Web服务端产生的,然后发给浏览器客户端。
let http = require('http');
let fs = require('fs');
let path = require('path');
let mime = require('mime');
let crypto = require('crypto');
http.createServer(function (req, res) {
    let file = path.join(__dirname, req.url);
    fs.stat(file, (err, stat) => {
        if (err) {
            sendError(err, req, res, file, stat);
        } else {
            let ifNoneMatch = req.headers['if-none-match'];
            let etag = crypto.createHash('sha1').update(stat.ctime.toGMTString() + stat.size).digest('hex');
            if (ifNoneMatch) {
                if (ifNoneMatch == etag) {
                    res.writeHead(304);
                    res.end();
                } else {
                    send(req, res, file, etag);
                }
            } else {
                send(req, res, file, etag);
            }
        }
    });
}).listen(8080);
function send(req, res, file, etag) {
    res.setHeader('ETag', etag);
    res.writeHead(200, { 'Content-Type': mime.lookup(file) });
    fs.createReadStream(file).pipe(res);
}
function sendError(err, req, res, file, etag) {
    res.writeHead(400, { "Content-Type": 'text/html' });
    res.end(err ? err.toString() : "Not Found");
}
Cache-Control:private, max-age=60, no-cache
let http = require('http');
let fs = require('fs');
let path = require('path');
let mime = require('mime');
let crypto = require('crypto');
http.createServer(function (req, res) {
    let file = path.join(__dirname, req.url);
    console.log(file);
    fs.stat(file, (err, stat) => {
        if (err) {
            sendError(err, req, res, file, stat);
        } else {
            send(req, res, file);
        }
    });
}).listen(8080);
function send(req, res, file) {
    let expires = new Date(Date.now() + 60 * 1000);
    res.setHeader('Expires', expires.toUTCString());
    res.setHeader('Cache-Control', 'max-age=60');
    res.writeHead(200, { 'Content-Type': mime.lookup(file) });
    fs.createReadStream(file).pipe(res);
}
function sendError(err, req, res, file, etag) {
    res.writeHead(400, { "Content-Type": 'text/html' });
    res.end(err ? err.toString() : "Not Found");
}