expires指令无法按状态码差异化设置缓存头,因其仅作用于2xx/3xx响应且不支持条件判断;可行方案是用add_header配合if $status变量在location中按需注入expires与cache-control,并确保cdn开启错误状态码缓存、头部一致且无private/no-store冲突。

直接用 expires 指令按状态码差异化设置缓存头不可行——它只作用于 2xx/3xx 响应,对 4xx/5xx 默认不生效,且不支持状态码条件判断。真正可行的方式是:用 add_header 配合 if + 状态码变量,在 location 中按需注入 Expires 和 Cache-Control,再确保 CDN 能识别并沿用这些头。
状态码与缓存策略必须语义匹配
不同错误状态码代表不同业务含义,缓存时长应体现其可重试性与稳定性:
- 200/301/302:内容稳定,适合长期缓存(如 1h~7d),提升 CDN 命中率
- 404:资源不存在,缓存过久会掩盖新上线路径;建议 1~5 分钟,防探测打垮后端
- 410(Gone):明确废弃,可缓存更久(如 1h),避免反复回源
- 500/502/503/504:服务临时异常,需快速失效、引导重试;建议 10~30 秒,防雪崩
用 if + $status 实现状态码条件注入
Nginx 的 $status 变量在响应阶段可用,配合 add_header ... always 可覆盖默认限制:
在目标 location 块中写入:
add_header Expires "" always;
add_header Cache-Control "" always;
然后逐条定义:
if ($status = 200) {
add_header Expires "access plus 1h" always;
add_header Cache-Control "public, max-age=3600" always;
}
if ($status = 404) {
add_header Expires "access plus 2m" always;
add_header Cache-Control "public, max-age=120" always;
}
if ($status ~ ^(50[0-4]|50[0-4])) {
add_header Expires "access plus 20s" always;
add_header Cache-Control "public, max-age=20" always;
}
注意:if 在 location 内可用,但不能嵌套;正则匹配 50x 推荐用 ~ ^(50[0-4])$ 更精确。
CDN 要真正生效,头部必须“可见且可信”
很多 CDN(如 Cloudflare、阿里云全站加速)默认不缓存 4xx/5xx,或忽略其缓存头。需确认以下三点:
- CDN 控制台已开启「缓存错误状态码」开关(常叫 “Cache Error Pages” 或 “Cache 4xx/5xx”)
- 响应中同时存在
Cache-Control和Expires,且值一致,避免 CDN 解析冲突 - 避免后端返回
Cache-Control: private或no-store—— 它们会覆盖你设的头;必要时加proxy_ignore_headers Cache-Control
静态资源建议改用 expires 指令统一管理
对于纯静态路径(如 /static/、/assets/),无需按状态码区分,直接用 expires 更简洁高效:
location /static/ {
alias /var/www/static/;
expires 30d;
add_header Cache-Control "public, immutable" always;
}
这类配置由 Nginx 内部处理,无 if 开销,且所有 2xx 响应自动带头,CDN 识别稳定。











