别让你的API慢成蜗牛:HTTP缓存核心原理与避坑指南

2026-06-02 10 0

你有没有遇到过这种窒息时刻:接口响应时间2秒,用户截图发群里,老板的眼神比502胶水还粘人。

你开始加机器、加Redis、加CDN,折腾一圈下来——还是2秒。

然后你绝望地发现,问题可能根本不在服务器,而在你根本不懂HTTP缓存

别急着划走。这篇文章不教你背协议文档,而是用实战告诉你,怎么让API飞起来。


先搞清楚:缓存到底是个什么东西

很多人对缓存的理解就是"把数据放内存里"。这个理解不能说错,只能说——Too young,Too simple,Sometimes naive。

HTTP缓存的本质是:让服务器少干活,让客户端自己解决问题。你每发一次同样的请求,服务器都得重新查库、组装数据、返回响应。但实际上,这个响应可能3小时内都不会变。你让服务器白干了3小时。

HTTP缓存协议设计了两种机制:

  • 强制缓存(Cache-Control):客户端直接用本地缓存,不问服务器
  • 协商缓存(Last-Modified / ETag):客户端问一下服务器,这个东西还能用吗

搞清楚这两个东西怎么配合,比你加十台机器管用。


Cache-Control:这是你必须搞懂的第一个头部

Cache-Control是HTTP缓存的核心担当。它不是一个值,是一堆指令的组合。常见的有:

  • max-age=秒数:缓存有效期,过了这个时间才需要重新请求
  • no-cache:不用本地缓存?不对,翻译错了——意思是每次都去服务器验证,别自作主张
  • no-store:这个才是真正禁用缓存,告诉浏览器连存都不要存
  • public:响应可以被任何缓存节点缓存(CDN、代理等)
  • private:只有客户端本地能缓存,CDN不行

最容易被搞混的是 no-cache 和 no-store。面试十个后端,九个答反。你品,你细品。

实战建议:

Cache-Control: max-age=300, public   // 数据5分钟内有效,可以进CDN
Cache-Control: no-cache, must-revalidate // 每次用,但要确认新鲜度
Cache-Control: private // 私人数据,别让CDN缓存!

ETag:省流量的好东西

很多人在Etag和Last-Modified之间纠结。我的建议是:两个都上,不吃亏

Last-Modified记录文件修改时间,精确到秒。Etag是你自定义的版本号,精确到内容hash。

ETag的工作流程是这样的:

客户端 GET /api/user/123
服务端 200 OK
         ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
         Content-Type: application/json
         响应体 {...}


客户端(再次请求)GET /api/user/123
         If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

服务端检查:
  - If-None-Match匹配 → 304 Not Modified(不返回body,只头部)
  - 不匹配 → 200 OK + 新ETag + 新body

304响应有多爽?你的body可能是50KB,304就只有头部,大概几十个字节。一次省50KB,一天算你10万次请求——省了5GB流量。

这就是为什么有些接口你感觉"没改什么但变快了"——因为它根本没返回body。


实战场景:哪些地方最应该加缓存

不是所有接口都值得缓存。加错了,轻则数据过期,重则用户看到别人的隐私。

适合缓存:

  • 业务配置、字典表(几乎不变)
  • 公开的列表数据(新闻列表、商品列表)
  • 用户头像、静态资源
  • 聚合查询结果(需要设较短max-age)

不适合缓存:

  • 包含用户个人数据的响应(private场景)
  • 实时数据(如股价、库存)——这个过期了会出大事
  • POST、PUT、DELETE等写操作的响应
  • 认证相关接口(token频繁变化)

还有一个极其容易被忽略的地方:JSONP和跨域请求的缓存。很多项目用了Corsisc这类中间件,默认把缓存头全清了。做完了发现所有接口都没缓存,一看配置——哦豁。


我见过最离谱的几个缓存反模式

反模式一:max-age=0 当作禁用缓存

有人以为 Cache-Control: max-age=0 就是禁用缓存。错!浏览器会在0秒后立刻验证——但它还是会缓存的!只是每次都去校验。

如果你想真的不缓存,正确答案是:

Cache-Control: no-store, no-cache, must-revalidate

反模式二:把用户私有数据设成public

我见过有工程师把所有接口设成 public,理由是"方便CDN缓存提速"。

你这是把用户A的订单数据缓存进CDN,然后用户B可能访问到。你想上社会新闻吗?

原则:任何涉及个人隐私的数据,必须 private 或禁止缓存。这条写进团队规范里都不为过。

反模式三:只在后端做缓存,前端乱来

后端设了一堆Cache-Control,结果前端发请求时加了个 ?t=时间戳,每次URL都变,缓存全部失效。

这属于——前端自己废了自己的武功,还回头怪后端慢。团队内部联调时,这个问题出现的频率高得离谱。


怎么验证你的缓存到底有没有生效

很多人设了一堆缓存头,但根本不知道怎么验证。工具很简单:Chrome开发者工具。

打开 Network 面板,勾选 Disable cache 关掉浏览器缓存做对比,然后:

  • Size 列:显示 from cache 就是命中了本地缓存
  • Status 列:304 就是服务端缓存验证生效
  • 右键点击请求 → Block request domain 可以模拟缓存过期场景

另外推荐一个命令:

curl -I https://你的接口地址
# 查看返回的头部信息,重点看:
# Cache-Control
# ETag
# Last-Modified
# Expires

很多线上问题,是从这个命令发现 ETags 缺失开始的。


一句话总结

HTTP缓存不是什么高深的技术,但它真的被严重低估了。你花两周开发的接口功能,可能因为一个 Cache-Control 设置错误,变成一个每次都打服务器的废物。

把缓存玩明白,比你买十台服务器便宜多了。

下次老板问你为什么接口慢,你就说——因为缓存没设对。

然后优雅地打开这篇文章。

相关文章

为什么别人已经在用AI自动化,你还在和服务器较劲?
为什么别人已经在用AI自动化,你还在和服务器较劲?
别再问我能不能用:gRPC真不是万能药,但这些场景它确实强到离谱
别再折腾云端AI了:我是如何把大模型跑在4GB内存的垃圾服务器上
【AI探索】当小龙虾遇上AI:新闻速递、奇技淫巧与我的翻车现场
我用OpenClaw这一年:真香、踩坑与意外惊喜

发布评论