nginx通过自定义proxy_cache_key将请求头(如accept-encoding、user-agent、cookie)纳入缓存键计算,实现同一url多版本缓存,并需配合vary响应头确保客户端正确识别变体。

静态资源本身是固定的,不随请求头变化而改变内容,所以“根据请求头内容缓存”本质上不是缓存不同内容,而是让 Nginx 生成**不同的缓存键(cache key)**,从而对同一 URL、但携带不同请求头(如 Accept-Encoding、Cookie、User-Agent 等)的请求,分别缓存多个变体。
关键:自定义 proxy_cache_key
Nginx 默认缓存键是 $scheme$proxy_host$request_uri,它不包含请求头。要实现按请求头区分缓存,必须显式修改 proxy_cache_key,把相关头部值纳入哈希计算。
- 例如,支持 gzip 和 brotli 压缩时,浏览器通过
Accept-Encoding告知服务端能力,后端返回不同压缩格式——若不区分缓存,可能把 gzip 版本返回给不支持的客户端 - 又如,带用户身份标识的静态 HTML(极少见),需根据
Cookie或Authorization区分缓存
常见按请求头缓存的场景与配置
1. 按 Accept-Encoding 缓存(推荐必配)
确保压缩版本不混用:
location /static/ {
proxy_cache my_cache;
proxy_cache_key "$scheme$host$request_uri$is_args$args$http_accept_encoding";
proxy_pass http://backend;
}
2. 按 User-Agent 缓存(谨慎使用)
仅在确实提供不同资源(如移动端 JS/CSS)时启用,否则会大幅增加缓存碎片:
proxy_cache_key "$scheme$host$request_uri$is_args$args$http_user_agent";
3. 按 Cookie 的某字段缓存(如会话 ID)
适用于含轻量个性化信息的静态片段(非主资源):
map $cookie_session_id $session_key {
default "";
"~^([a-zA-Z0-9]+)$" "$1";
}
proxy_cache_key "$scheme$host$request_uri$is_args$args$session_key";
配合响应头控制缓存行为
仅改 key 不够,还需确保后端响应头明确支持多变体:
- 返回
Vary: Accept-Encoding,告诉浏览器和中间缓存:“此响应依赖于 Accept-Encoding,别拿 gzip 版本给没声明支持的客户端” - Nginx 本身不自动加 Vary,需后端应用设置;若后端无法控制,可用
add_header Vary "Accept-Encoding";强制添加 - 注意:
Vary值必须与proxy_cache_key中实际使用的请求头严格一致,否则 CDN 或代理可能忽略缓存
验证是否生效
检查三处:
- 用
curl -I -H "Accept-Encoding: gzip" URL和curl -I -H "Accept-Encoding: br" URL,看两次响应的Etag或Last-Modified是否不同 - 查看 Nginx 缓存目录下是否生成了不同哈希前缀的文件(需开启
proxy_cache_path ... levels=1:2才能直观看到层级) - 响应头中是否有正确的
Vary字段,且其值与你 key 中引用的 header 名完全匹配











