强缓存与协商缓存的实现机制

文章目录


前言

强缓存与协商缓存的实现机制

1. 强缓存(强制缓存)

特点:浏览器直接从本地缓存读取资源,不发送请求到服务器。

实现方式:通过 Cache-ControlExpires 响应头控制。

(1) Cache-Control(HTTP/1.1 标准,优先级更高)

• 常见指令:

max-age=<seconds>:缓存有效期(如 max-age=3600 表示 1 小时内有效)。

no-cache:不使用强缓存,直接进入协商缓存(向服务器验证)。

no-store:完全禁用缓存,每次请求都重新获取资源。

public:允许代理服务器缓存(默认 private 仅浏览器缓存)。

immutable:资源永不变,浏览器直接使用缓存(适用于版本化文件名如 main.a1b2c3.js)。

• 示例:

http 复制代码
Cache-Control: public, max-age=3600

(2) Expires(HTTP/1.0 遗留,优先级低于 Cache-Control

• 指定一个绝对过期时间(GMT 格式),若本地时间超过该时间则缓存失效。

• 示例:

http 复制代码
Expires: Wed, 21 Oct 2025 07:28:00 GMT

强缓存生效流程

  1. 浏览器请求资源时,检查 Cache-Control/Expires
  2. 若未过期,直接从 内存缓存(Memory Cache) 或 磁盘缓存(Disk Cache) 加载,HTTP 状态码显示 200 (from cache)。
  3. 若已过期,进入协商缓存流程。

2. 协商缓存(对比缓存)

特点:浏览器向服务器验证缓存是否有效,可能返回 304(Not Modified) 继续使用缓存。

实现方式:通过 Last-Modified/If-Modified-SinceETag/If-None-Match 两组头部控制。

(1) Last-Modified + If-Modified-Since

• 服务器返回 Last-Modified:资源的最后修改时间(GMT 格式)。

• 浏览器下次请求:携带 If-Modified-Since(值为上次的 Last-Modified)。

• 服务器检查:

• 若资源未修改(时间未变),返回 304 Not Modified,浏览器使用缓存。

• 若已修改,返回 200 OK 和新资源。

• 示例:

http 复制代码
# 首次请求(服务器响应)
Last-Modified: Wed, 21 Oct 2025 07:28:00 GMT

# 再次请求(浏览器携带)
If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT

(2) ETag + If-None-Match(更精准)

• 服务器返回 ETag:资源的唯一标识符(如哈希值)。

• 浏览器下次请求:携带 If-None-Match(值为上次的 ETag)。

• 服务器检查:

• 若 ETag 匹配,返回 304 Not Modified。

• 若不匹配,返回 200 OK 和新资源。

• 示例:

http 复制代码
# 首次请求(服务器响应)
ETag: "33a64df551425fcc55e4d42a148795d9"

# 再次请求(浏览器携带)
If-None-Match: "33a64df551425fcc55e4d42a148795d9"

协商缓存生效流程

  1. 浏览器发现强缓存失效(或 no-cache),携带 If-Modified-SinceIf-None-Match 向服务器发起请求。

  2. 服务器验证资源是否变化:

    • 未变化 → 返回 304,浏览器使用缓存。

    • 已变化 → 返回 200 和新资源。


对比总结

缓存类型 实现方式 优先级 特点
强缓存 Cache-Control/Expires 直接读缓存,不请求服务器。
协商缓存 Last-Modified/ETag 需向服务器验证,可能返回 304。

实际应用建议

  1. 静态资源(如 JS/CSS/图片):

    • 使用强缓存 + 文件名哈希(如 main.a1b2c3.js),设置 Cache-Control: max-age=31536000, immutable

  2. 动态资源(如 API 数据):

    • 使用 Cache-Control: no-cache + ETag,确保实时性。

  3. 避免缓存问题:

    • 修改资源时更新文件名或 URL 参数(如 ?v=2)。

通过合理配置,可显著减少网络请求,提升页面加载速度! 🚀


1. 缓存配置的三种主要实现方式

(1) 后端代码控制(如Node.js/Java/Python)

适用场景:动态API、需要业务逻辑判断是否缓存。

示例(Node.js Express):

javascript 复制代码
app.get('/data', (req, res) => {
  // 强缓存:1小时有效
  res.set('Cache-Control', 'public, max-age=3600');
  
  // 协商缓存:ETag
  const data = { id: 1, name: 'Example' };
  const etag = require('crypto').createHash('md5').update(JSON.stringify(data)).digest('hex');
  res.set('ETag', etag);
  
  // 检查客户端If-None-Match
  if (req.headers['if-none-match'] === etag) {
    return res.status(304).end(); // 返回304,使用缓存
  }
  
  res.json(data);
});

(2) Web服务器配置(如Nginx/Apache)

适用场景:静态资源(HTML/CSS/JS/图片)的缓存。

Nginx示例:

nginx 复制代码
server {
    location /static/ {
        # 强缓存:1年(适用于版本化文件名如main.a1b2c3.js)
        add_header Cache-Control "public, max-age=31536000, immutable";
        
        # 协商缓存:Last-Modified/ETag(默认启用,无需额外配置)
    }

    location /api/ {
        # 动态接口禁用强缓存,只用协商缓存
        add_header Cache-Control "no-cache";
        # Nginx会自动处理ETag/Last-Modified(需确保后端未覆盖)
    }
}

(3) CDN控制(如Cloudflare/AWS CloudFront)

适用场景:全球加速的静态资源缓存。

Cloudflare规则示例:

• 缓存规则:匹配URL路径(如/images/*),设置缓存有效期(如1小时)。

• 边缘缓存TTL:覆盖源站的Cache-Control头。


2. 缓存策略选择与优先级
(1) 缓存配置的优先级

  1. CDN设置 > Nginx配置 > 后端代码

    • 如果CDN设置了缓存规则,它会覆盖Nginx或后端的Cache-Control头。

    • 如果Nginx配置了add_header,它会覆盖后端代码的响应头。

(2) 如何决定使用哪种方式?

场景 推荐方式 理由
静态资源(JS/CSS/图片) Nginx/CDN 高效、无需业务逻辑,直接通过文件名哈希(如main.a1b2c3.js)和强缓存优化。
动态API数据 后端代码 需要根据业务逻辑判断是否缓存(如用户隐私数据不可缓存)。
全局缓存策略 CDN 统一管理所有边缘节点的缓存行为,适合多地域部署。

(3) 强制禁用缓存的场景

• 需要实时数据的API(如股票价格):

http 复制代码
Cache-Control: no-store

• 用户敏感信息(如个人资料):

http 复制代码
Cache-Control: private, no-cache

3. 实战建议
(1) 静态资源优化

nginx 复制代码
location /assets/ {
    # 文件名带哈希(如main.a1b2c3.js),强缓存1年
    add_header Cache-Control "public, max-age=31536000, immutable";
}

• 使用Webpack/Vite等工具生成哈希文件名,确保内容变化后URL改变。

(2) 动态API优化

javascript 复制代码
// 后端代码(Express/Koa)
res.set({
    'Cache-Control': 'no-cache', // 禁用强缓存,但允许协商缓存
    'ETag': generateETag(data)   // 基于内容生成ETag
});

(3) 调试缓存行为

• Chrome DevTools → Network → 查看请求头(Cache-Control/ETag)和响应状态(200/304)。

• cURL命令测试:

bash 复制代码
curl -I http://example.com/resource
# 检查响应头中的Cache-Control/ETag

总结

• 谁控制缓存?

• 静态资源 → Nginx/CDN

• 动态API → 后端代码

• 全局策略 → CDN

• 如何选择?

• 强缓存:Cache-Control: max-age=3600(Nginx/CDN优先)。

• 协商缓存:ETag/Last-Modified(后端或Nginx自动处理)。

• 调试工具:Chrome DevTools、cURL、Web服务器日志。

合理配置缓存可显著提升性能,减少服务器压力! 🚀

相关推荐
Aliano2174 小时前
Pinecone向量库 VS Redis
数据库·redis·缓存·pinecone向量库
LUCIAZZZ11 小时前
Caffeine快速入门
java·后端·spring·缓存·操作系统·springboot
中草药z11 小时前
【Redis】哨兵机制和集群
数据库·redis·缓存·集群·cluster·哨兵·数据分区算法
zizisuo20 小时前
2.Redis高阶实战
数据库·redis·缓存
猫头虎1 天前
多线程“CPU 飙高”问题:如何确保配置的线程数与CPU核数匹配(Java、GoLang、Python )中的最佳实践解决方案
java·python·缓存·golang·需求分析·极限编程·结对编程
张哈大1 天前
【Redis | 基础总结篇 】
数据库·redis·缓存
鬼义II虎神1 天前
Django缓存框架API
python·缓存·django
cooldream20091 天前
缓存与数据库的高效读写流程解析
数据库·缓存·系统架构师
编程在手天下我有1 天前
缓存:缓解读库压力的高效方案与应用实践
数据库·缓存·性能优化·软件开发·系统设计·技术架构