├── .gitignore ├── README.md ├── index.html ├── package.json ├── server.js └── static ├── index.css └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodejs设置缓存demo 2 | 3 | ## 开始 4 | ``` 5 | npm install 6 | npm start 7 | ``` 8 | 9 | ## 博客 10 | [前端缓存最佳实践](https://juejin.im/post/5c136bd16fb9a049d37efc47) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hello World 8 | 9 | 10 | 11 |

Hello World

12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-control-nodejs-demo", 3 | "version": "1.0.0", 4 | "description": "cache-control demo for nodejs", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "etag": "^1.8.1", 13 | "fresh": "^0.5.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const http = require('http'); 2 | const fs = require('fs'); 3 | const url = require('url'); 4 | const path = require('path'); 5 | const etag = require('etag'); 6 | const fresh = require('fresh'); 7 | 8 | const server = http.createServer(function (req, res) { 9 | let filePath, isHtml, isFresh; 10 | const pathname = url.parse(req.url, true).pathname; 11 | //根据请求路径取文件绝对路径 12 | if (pathname === '/') { 13 | filePath = path.join(__dirname, '/index.html'); 14 | isHtml = true; 15 | } else { 16 | filePath = path.join(__dirname, 'static', pathname); 17 | isHtml = false; 18 | } 19 | 20 | // 读取文件描述信息,用于计算etag及设置Last-Modified 21 | fs.stat(filePath, function (err, stat) { 22 | if (err) { 23 | res.writeHead(404, 'not found'); 24 | res.end('

404 Not Found

'); 25 | } else { 26 | if (isHtml) { 27 | // html文件使用协商缓存 28 | const lastModified = stat.mtime.toUTCString(); 29 | const fileEtag = etag(stat); 30 | res.setHeader('Cache-Control', 'public, max-age=0'); 31 | res.setHeader('Last-Modified', lastModified); 32 | res.setHeader('ETag', fileEtag); 33 | 34 | // 根据请求头判断缓存是否是最新的 35 | isFresh = fresh(req.headers, { 36 | 'etag': fileEtag, 37 | 'last-modified': lastModified 38 | }); 39 | } else { 40 | // 其他静态资源使用强缓存 41 | res.setHeader('Cache-Control', 'public, max-age=3600'); 42 | } 43 | 44 | fs.readFile(filePath, 'utf-8', function (err, fileContent) { 45 | if (err) { 46 | res.writeHead(404, 'not found'); 47 | res.end('

404 Not Found

'); 48 | } else { 49 | if (isHtml && isFresh) { 50 | //如果缓存是最新的 则返回304状态码 51 | //由于其他资源使用了强缓存 所以不会出现304 52 | res.writeHead(304, 'Not Modified'); 53 | } else { 54 | res.write(fileContent, 'utf-8'); 55 | } 56 | 57 | res.end(); 58 | } 59 | }); 60 | } 61 | }); 62 | }); 63 | server.listen(8080); 64 | console.log('server is running on http://localhost:8080/'); -------------------------------------------------------------------------------- /static/index.css: -------------------------------------------------------------------------------- 1 | h1{ 2 | color: #F00; 3 | } -------------------------------------------------------------------------------- /static/index.js: -------------------------------------------------------------------------------- 1 | console.log('hello world'); --------------------------------------------------------------------------------