状态码:先看类别,再看具体值
| 类别 | 含义 | 常见值 |
|---|---|---|
| 1xx | 信息 | 100 Continue、101 协议切换 |
| 2xx | 成功 | 200、201 已创建、204 无内容 |
| 3xx | 重定向 | 301 永久、302 临时、304 未修改、307/308 保持方法 |
| 4xx | 客户端错误 | 400、401 未认证、403 无权限、404、409 冲突、429 限流 |
| 5xx | 服务端错误 | 500、502 网关错误、503 不可用、504 网关超时 |
四个容易混淆的点
- 401 vs 403:401 是「你是谁」,403 是「知道你是谁,但不给你」;
- 301 vs 308:同为永久重定向,308 保证请求方法与请求体不变;302 与 307 的关系同理;
- 200 但业务失败:不少接口用 200 + 业务错误码表示失败,客户端必须读响应体;
- 502 vs 504:都是网关问题,502 是上游返回了无效响应,504 是上游超时。
缓存头速查
| 响应头 | 作用 | 常用值 |
|---|---|---|
| Cache-Control | 缓存策略主体 | no-store / no-cache / max-age=3600 / immutable |
| ETag | 资源指纹,用于协商缓存 | "abc123"(配合 If-None-Match) |
| Last-Modified | 最后修改时间 | 配合 If-Modified-Since |
| Vary | 按哪些请求头区分缓存 | Accept-Encoding、Accept-Language |
一套可直接套用的策略
- 文件名带哈希的构建产物:Cache-Control: public, max-age=31536000, immutable(文件名一变即更新);
- HTML 页面:max-age=0, must-revalidate(保证发布后即时生效);
- API 响应:私有数据用 no-store,可共享的公开数据用较短 max-age 配合 ETag;
- 静态图片与字体:长 max-age,并配合 Vary: Accept-Encoding。
常见坑
- 只设 max-age 不设 immutable:用户刷新时仍会发起验证请求;
- 给 HTML 设长缓存:发版后用户看到旧页面,且中间缓存可能长期不回源;
- ETag 与 CDN 配置不一致:导致协商缓存失效或缓存错乱;
- 忽略 Vary:可能把 gzip 内容发给不支持压缩的客户端。
排查建议
用浏览器开发者工具的 Network 面板看「大小」列:显示 from disk cache 或 memory cache 说明命中强缓存;显示 304 说明命中协商缓存。再核对响应头里的 Cache-Control 是否与预期一致,通常一步就能定位问题。服务端排查时,逐层检查:源站响应头 → CDN 缓存规则 → 浏览器缓存状态。
常见问题
no-cache 是不缓存吗?不是。no-cache 表示「可以缓存,但每次使用前必须向服务器验证」,真正完全不缓存是 no-store。304 为什么没有响应体?它是「未修改」的标记,浏览器直接使用本地副本,因此不带正文。接口要不要缓存?看数据是否共享:用户私有数据不应被中间缓存共享,公开且变更不频繁的数据可以。
状态码与缓存头的配合
状态码不仅是给调用方看的,它也参与缓存决策,两者必须一起设计。
- 可缓存性取决于方法与状态码:默认情况下,成功响应可被缓存,而错误响应通常不被缓存。若希望错误也被短暂缓存以减轻下游压力,需要显式声明,并严格控制时长。
- 重定向与永久性:永久重定向应谨慎使用,一旦浏览器缓存就很难撤除;临时重定向适合灰度与维护场景。
- 验证器要用对:内容有变更时给出新的验证器,未变更时返回表示“未修改”的结果,让客户端复用本地副本,能显著降低带宽。
- 区分“未找到”与“已删除”:前者表示当前不存在,后者表示曾经存在并已移除。搜索引擎与客户端对二者的处理不同,混用会造成索引异常。
- 冲突与前置条件:并发更新应使用前置条件相关的状态码与验证器配合,让调用方能区分“请求有误”与“数据被他人修改”。
常见误区
把所有错误都返回同一个状态码会让客户端无法区分处理策略,例如需要重试的暂时性错误与需要修改请求的参数错误被混在一起。为不同语义分配稳定且明确的状态码,是接口可用性的基础工作。
与监控的配合
状态码分布本身就是重要的监控指标:客户端错误比例突然上升通常意味着调用方变更或文档有误,服务端错误上升则指向自身缺陷。把不同类别的状态码分开统计并设阈值告警,比只看总错误率更能快速定位问题来源。