强制缓存和协商缓存是什么

231 阅读4分钟

以下是关于强制缓存和协商缓存的详细解释:

1. 强制缓存(Cache-Control 和 Expires)

概念

  • 强制缓存

    • 强制缓存是一种缓存策略,当浏览器请求资源时,服务器会在响应头中设置 Cache-Control 或 Expires 字段,告诉浏览器该资源可以缓存多长时间。在缓存有效期内,浏览器将直接从本地缓存中获取资源,而无需向服务器发送请求。

实现方式

  • Cache-Control

    • Cache-Control 是 HTTP/1.1 中的缓存控制字段,具有更多的选项和更灵活的配置。例如:

      • public:表示响应可以被任何缓存(包括代理服务器和客户端)缓存。
      • private:表示响应只能被客户端缓存,不能被代理服务器缓存。
      • max-age:指定缓存的时长(以秒为单位),例如 Cache-Control: public, max-age=3600 表示资源可以被缓存 1 小时。
      • no-cache:表示在使用缓存前必须先与服务器确认缓存的有效性,并不是不缓存资源。
      • no-store:表示不允许缓存该资源,每次都要从服务器获取。
  • Expires

    • Expires 是 HTTP/1.0 中的缓存控制字段,它指定一个绝对的过期时间。例如:

      • Expires: Wed, 21 Oct 2025 07:28:00 GMT
    • 由于 Expires 是一个绝对时间,可能会受客户端和服务器时间不一致的影响,因此在 HTTP/1.1 中更推荐使用 Cache-Control

代码示例

  • 服务器端设置(Node.js 示例)

收起

javascript

const http = require('http');
const fs = require('fs');

http.createServer((req, res) => {
  if (req.url === '/') {
    res.writeHead(200, {
      'Cache-Control': 'public, max-age=3600',
      'Content-Type': 'text/html'
    });
    fs.createReadStream('index.html').pipe(res);
  }
}).listen(3000);
  • 解释

    • 当客户端请求根路径时,服务器返回 index.html 文件,并设置 Cache-Control 为 public, max-age=3600,表示该文件可以被缓存 1 小时。

2. 协商缓存(Last-Modified 和 ETag)

概念

  • 协商缓存

    • 当强制缓存失效后,浏览器会向服务器发送请求,但不是直接请求资源,而是发送一个请求验证缓存是否仍然有效。这是通过 Last-Modified 和 ETag 实现的。

实现方式

  • Last-Modified 和 If-Modified-Since

    • Last-Modified

      • 服务器在响应头中设置 Last-Modified,表示资源的最后修改时间。例如:

        • Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT
    • If-Modified-Since

      • 当缓存失效后,浏览器会在请求头中带上 If-Modified-Since,其值为之前服务器返回的 Last-Modified 值。
      • 服务器收到请求后,会将该时间与资源的实际修改时间比较,如果资源未修改,返回 304 Not Modified 状态码,让浏览器继续使用缓存;如果修改了,返回 200 状态码和新资源。
  • ETag 和 If-None-Match

    • ETag

      • 服务器在响应头中设置 ETag,它是资源的唯一标识符,通常是一个哈希值或版本号。例如:

        • ETag: "123456789abcdef"
    • If-None-Match

      • 当缓存失效后,浏览器在请求头中带上 If-None-Match,其值为之前服务器返回的 ETag 值。
      • 服务器收到请求后,将该 ETag 值与当前资源的 ETag 比较,若相同,返回 304 Not Modified,让浏览器使用缓存;不同则返回 200 状态码和新资源。

代码示例

  • 服务器端设置(Node.js 示例)

收起

javascript

const http = require('http');
const fs = require('fs');
const crypto = require('crypto');

http.createServer((req, res) => {
  if (req.url === '/') {
    const file = fs.statSync('index.html');
    const etag = crypto.createHash('md5').update(fs.readFileSync('index.html')).digest('hex');
    const lastModified = file.mtime.toUTCString();

    if (req.headers['if-none-match'] === etag && req.headers['if-modified-since'] === lastModified) {
      res.writeHead(304);
      res.end();
    } else {
      res.writeHead(200, {
        'Content-Type': 'text/html',
        'ETag': etag,
        'Last-Modified': lastModified
      });
      fs.createReadStream('index.html').pipe(res);
    }
  }
}).listen(3000);
  • 解释

    • 服务器计算 index.html 的 ETag(使用 MD5 哈希)和 Last-Modified(文件的修改时间)。
    • 如果请求头中的 If-None-Match 和 If-Modified-Since 与当前的 ETag 和 Last-Modified 相同,返回 304 状态码;否则,返回新资源并更新 ETag 和 Last-Modified

3. 应用场景

强制缓存

  • 静态资源

    • 对于长时间不更新的静态资源(如 CSS 文件、JavaScript 文件、图片等),可以使用强制缓存,减少重复请求,提高性能。

协商缓存

  • 动态资源或经常更新的资源

    • 对于可能会更新的资源(如 API 数据、动态页面),使用协商缓存可以在资源更新时让浏览器及时获取最新资源,同时避免不必要的资源下载。

4. 总结

  • 强制缓存

    • 直接使用本地缓存,减少请求次数,适用于长时间不更新的资源。
  • 协商缓存

    • 先与服务器协商,根据资源是否更新决定是否使用缓存,适用于可能更新的资源。

在实际的 Web 开发中,根据资源的性质和更新频率选择合适的缓存策略,可以有效提高网站性能和用户体验。同时,根据不同的开发语言和服务器,可以使用不同的工具和框架来设置这些缓存策略。