微信登录

静态文件服务 - 缓存设置 - 配置静态文件缓存

静态文件服务 - 缓存设置 - 配置静态文件缓存

在 Node.js 中构建静态文件服务时,合理配置静态文件缓存可以显著提升应用的性能和响应速度。本文将深入探讨如何在 Node.js 中配置静态文件缓存,以及不同缓存策略的应用场景和实现方法。

缓存的重要性

在 Web 应用中,静态文件(如 CSS、JavaScript、图片等)通常不会频繁更新。如果每次用户请求这些文件时都从服务器重新获取,会增加服务器的负载和用户的等待时间。通过使用缓存,浏览器可以将这些文件存储在本地,下次请求时直接从本地读取,从而减少不必要的网络请求,提高页面加载速度。

缓存策略

常见的缓存策略有两种:强缓存和协商缓存。

强缓存

强缓存是指浏览器直接从本地缓存中读取文件,而不需要向服务器发送请求。通过设置响应头 Cache-ControlExpires 来控制强缓存。

  • Cache-Control:是一个通用的缓存控制头,用于指定缓存的行为,如 max-age 表示缓存的最大时间(以秒为单位)。
  • Expires:是一个 HTTP 1.0 时代的缓存控制头,指定缓存的过期时间,不过由于它依赖于客户端和服务器的时间同步,现在一般使用 Cache-Control 替代。

协商缓存

协商缓存是指浏览器在使用本地缓存之前,会先向服务器发送一个请求,询问服务器该文件是否有更新。如果文件没有更新,服务器返回 304 状态码,浏览器直接使用本地缓存;如果文件有更新,服务器返回 200 状态码和新的文件内容。通过设置响应头 ETagLast-Modified 来控制协商缓存。

  • ETag:是一个文件的唯一标识符,服务器可以根据文件的内容生成一个 ETag。
  • Last-Modified:指定文件的最后修改时间。

Node.js 实现静态文件缓存

强缓存示例

以下是一个使用 Node.js 原生 http 模块实现强缓存的示例代码:

  1. const http = require('http');
  2. const fs = require('fs');
  3. const path = require('path');
  4. const server = http.createServer((req, res) => {
  5. const filePath = path.join(__dirname, 'public', req.url === '/'? 'index.html' : req.url);
  6. fs.stat(filePath, (err, stats) => {
  7. if (err) {
  8. res.statusCode = 404;
  9. res.end('File not found');
  10. return;
  11. }
  12. // 设置强缓存,缓存时间为 3600 秒(1 小时)
  13. res.setHeader('Cache-Control', 'public, max-age=3600');
  14. fs.createReadStream(filePath).pipe(res);
  15. });
  16. });
  17. server.listen(3000, () => {
  18. console.log('Server is running on port 3000');
  19. });

在上述代码中,我们通过设置 Cache-Control 头来控制强缓存,将缓存时间设置为 3600 秒。

协商缓存示例

以下是一个使用 Node.js 原生 http 模块实现协商缓存的示例代码:

  1. const http = require('http');
  2. const fs = require('fs');
  3. const path = require('path');
  4. const crypto = require('crypto');
  5. const server = http.createServer((req, res) => {
  6. const filePath = path.join(__dirname, 'public', req.url === '/'? 'index.html' : req.url);
  7. fs.readFile(filePath, (err, data) => {
  8. if (err) {
  9. res.statusCode = 404;
  10. res.end('File not found');
  11. return;
  12. }
  13. // 生成 ETag
  14. const hash = crypto.createHash('md5').update(data).digest('hex');
  15. const etag = `"${hash}"`;
  16. const ifNoneMatch = req.headers['if-none-match'];
  17. if (ifNoneMatch === etag) {
  18. res.statusCode = 304;
  19. res.end();
  20. return;
  21. }
  22. // 设置 ETag
  23. res.setHeader('ETag', etag);
  24. res.end(data);
  25. });
  26. });
  27. server.listen(3000, () => {
  28. console.log('Server is running on port 3000');
  29. });

在上述代码中,我们通过生成文件的 MD5 哈希值作为 ETag,并在响应头中设置 ETag。当浏览器再次请求该文件时,会在请求头中携带 If-None-Match 字段,服务器比较 If-None-MatchETag 的值,如果相同则返回 304 状态码,否则返回新的文件内容。

总结

缓存策略 控制头 优点 缺点 适用场景
强缓存 Cache-ControlExpires 减少服务器请求,提高页面加载速度 缓存时间内文件更新后客户端无法及时获取 不经常更新的静态文件,如图片、CSS、JavaScript 等
协商缓存 ETagLast-Modified 确保客户端获取到最新的文件内容 需要向服务器发送请求进行验证,增加了一定的开销 可能会频繁更新的静态文件

通过合理配置静态文件缓存,可以在提升应用性能的同时,确保客户端始终获取到最新的文件内容。在实际开发中,可以根据文件的更新频率和业务需求选择合适的缓存策略。

静态文件服务 - 缓存设置 - 配置静态文件缓存