Nginx 不支持将 HEAD 请求自动转为 GET 去上游获取并缓存响应体;proxy_cache_convert_head 仅控制缓存命中时是否复用已有 GET 响应头响应 HEAD,不改变转发行为。

Nginx 本身不支持直接将 HEAD 请求“转换为 GET”并缓存其响应体,proxy_cache_convert_head off(默认)或 on 的行为常被误解。实际上,proxy_cache_convert_head 并非用于“把 HEAD 变成 GET 去发起上游请求”,而是控制:当缓存中**已存在某 URI 对应的完整 GET 响应(含响应体)时**,是否允许用该缓存条目来直接响应后续的 HEAD 请求。
proxy_cache_convert_head 的真实作用
它只影响缓存命中场景下的响应复用逻辑,不改变代理转发行为:
- 若设为
on(Nginx 1.17.6+ 默认),且缓存中已有该 URI 的有效 GET 缓存(200、带Content-Length或Transfer-Encoding),则 Nginx 会截掉响应体、仅返回响应头,用以满足HEAD请求; - 若设为
off,Nginx 对HEAD请求始终原样转发给上游,不复用 GET 缓存,即使缓存里有对应内容; - 它不会让 Nginx 主动对上游发一个 GET 请求来替代 HEAD——这是关键误区。
想让 HEAD 请求也触发 GET 缓存写入?需主动构造
若目标是“让 HEAD 请求也能最终缓存到完整响应体”,必须让 Nginx 实际发出 GET 请求去上游获取内容。可行方式是:在 location 中通过 if + proxy_method 强制改写请求方法,并确保缓存策略覆盖该路径:
location /api/ {
proxy_pass https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e;
proxy_cache my_cache;
proxy_cache_valid 200 10m;
<pre class="brush:php;toolbar:false;"># 拦截 HEAD 请求,转为 GET 发往上游
if ($request_method = HEAD) {
proxy_method GET;
# 可选:清除可能干扰缓存的头
proxy_set_header Content-Length "";
proxy_set_header Content-Type "";
}}
⚠️ 注意:if 在 location 中使用有局限,更健壮做法是用 map 预定义变量:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
map $request_method $upstream_method {
default $request_method;
HEAD GET;
}
<p>server {
location /api/ {
proxy_pass <a href="https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e">https://www.php.cn/link/65b5b8d1f89bf53a5713bc3afdd83e9e</a>;
proxy_method $upstream_method;
proxy_cache my_cache;
proxy_cache_valid 200 10m;</p><h1>确保 HEAD 和 GET 共享同一缓存 key</h1><pre class="brush:php;toolbar:false;"> proxy_cache_key "$scheme$request_method$host$request_uri";
}}
缓存 KEY 必须统一,否则 HEAD/GET 被视为不同资源
默认 proxy_cache_key 包含 $request_method,导致 HEAD /a 和 GET /a 缓存键不同,无法复用。必须显式去掉方法维度:
- 设置
proxy_cache_key "$scheme$host$request_uri$is_args$args"; - 配合
proxy_method GET(对 HEAD),才能让两者写入/读取同一个缓存条目; - 同时需确保上游对 GET 返回可缓存响应(如
Cache-Control: public, max-age=60)。
验证是否生效
通过响应头和日志确认:
- 查看
X-Proxy-Cache(自定义)或Age头判断是否命中缓存; - 开启
log_format记录$upstream_http_x_cache或$cache_status; - 用
curl -I发 HEAD,再用curl -v发 GET,观察两次是否都返回HIT且Age相同。










