在 nginx 中,若缓存键包含协议头(如 $scheme),必须确保 proxy_cache_key 显式拼接该变量,否则默认行为会忽略协议差异导致 http 和 https 请求共用同一份缓存。正确做法是在配置中定义包含 $scheme 的缓存键,例如 $scheme$request_method$host$request_uri,这样当请求协议从 http 变为 https 时,nginx 会生成不同的缓存键,从而区分并存储独立的响应内容。

如何配置包含协议的缓存键
要区分不同协议的缓存,需要在 location 块中设置 proxy_cache_key 指令。默认的缓存键通常只包含主机名和 URI,这会导致同一个 URL 无论通过 HTTP 还是 HTTPS 访问,都命中相同的缓存文件。通过在键中加入 $scheme,可以强制 Nginx 根据协议类型生成唯一的缓存标识。

server {
listen 80;
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location /api/ {
proxy_pass http://backend;
proxy_cache my_cache;
# 关键配置:将协议加入缓存键
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 10m;
}
}
上述配置中,proxy_cache_key 使用了双引号包裹的字符串,其中 $scheme 会解析为 http 或 https。这意味着对于 /api/data 这个路径,HTTP 请求的缓存键将是 httpexample.com/api/data,而 HTTPS 请求的缓存键将是 httpsexample.com/api/data。两者在磁盘上会被存储为不同的文件,互不干扰。
验证缓存键是否生效及冲突排查
配置完成后,需要验证 Nginx 是否真的按照新的键进行缓存。可以通过检查 Nginx 的错误日志或使用 curl 模拟不同协议的请求来观察缓存命中情况。如果未看到预期的区分效果,通常是因为缓存键配置未正确加载,或者上游服务器返回了禁止缓存的头信息。

# 模拟 HTTP 请求 $ curl -I http://example.com/api/data # 观察响应头中的 X-Cache 状态 # 模拟 HTTPS 请求 $ curl -Ik https://example.com/api/data # 观察响应头中的 X-Cache 状态
在实际操作中,如果 X-Cache 显示为 HIT,但发现 HTTP 和 HTTPS 的内容不一致,说明缓存键可能未包含协议。反之,如果两者都显示 HIT 且内容一致,则确认缓存键已正确区分协议。此外,需确保后端服务没有发送 Cache-Control: no-cache 等指令,否则即使键不同,Nginx 也不会缓存响应。
基于 $scheme 变量在不同环境下的具体表现
当使用 $scheme 作为缓存键的一部分时,其值严格取决于客户端与 Nginx 之间的连接协议。如果 Nginx 位于反向代理之后,且前端负载均衡器终止了 SSL,那么 Nginx 接收到的始终是 HTTP 请求,此时 $scheme 始终为 http,无法区分原始客户端的协议意图。在这种情况下,应改用 $http_x_forwarded_proto 变量来获取原始协议。
例如,在 AWS ALB 或 Cloudflare 后方的 Nginx 配置中,若直接依赖 $scheme,所有流量都会被视为 HTTP 缓存。正确的做法是修改缓存键为:proxy_cache_key "$http_x_forwarded_proto$request_method$host$request_uri";。这样,即使内部通信是 HTTP,也能根据前端传来的 X-Forwarded-Proto 头正确区分缓存。这种细节在处理混合协议入口时至关重要,避免因协议识别错误导致的缓存污染或安全数据泄露。


















