用 map 预定义 $scheme 到协议前缀的映射,可在配置加载时固化转换逻辑,避免每次请求执行 if 判断和 rewrite,降低 cpu 开销与延迟;map 必须置于 http 块内且仅定义一次。

直接用 map 指令预定义 $scheme 对应的协议前缀,可跳过运行时判断逻辑,避免 Nginx 在每次请求中反复解析 scheme 并触发冗余重定向匹配,从而减少 CPU 开销和延迟。
用 map 预计算 scheme 到协议字符串的映射
Nginx 的 map 指令在配置加载阶段就完成变量映射关系的初始化,属于静态查表操作。将 $scheme 映射为完整协议字符串(如 "http://" 或 "https://"),后续就能直接拼接使用,无需在 if 或 rewrite 中重复判断。
- 在
http块中定义:
map $scheme $proto {
http "http://";
https "https://";
}
这样,$proto 就是确定值,不依赖请求处理流程,也不触发条件分支计算。
替代 if + rewrite 的重定向写法
常见错误是用 if ($scheme = http) { rewrite ^(.*)$ https://$host permanent; }——这会让 Nginx 每次都执行 if 判断、正则捕获、字符串拼接和重定向状态码生成,开销明显。
- 改用
return+$proto映射结果,更轻量:
server {
listen 80;
server_name example.com;
return 301 $proto$host$request_uri;
}
注意:此处 $proto 在 80 端口下恒为 "http://",但实际应配合 HTTPS server 块中的 map 定义统一使用。真正关键的是——把协议判断从「每次请求执行」变为「配置加载时固化」。
确保 map 定义位置正确且被复用
map 必须定义在 http 块内,不能放在 server 或 location 中;且只要定义一次,所有 server 块都能引用 $proto。
- 不要在多个 server 块里重复写 map
- 避免在 map 中引用未定义或动态变化的变量(如
$host),否则 map 失效,退化为运行时计算 - 若需区分 HTTP/HTTPS 的不同行为(如跳转目标域名),可扩展 map,例如:
map $scheme$host $redirect_to {<br> ~^https?example\.com$ "https://www.example.com$request_uri";<br>},但需谨慎控制正则复杂度
验证是否生效:看响应头与日志
部署后用 curl -I http://example.com 观察是否返回 301 及 Location 是否含正确协议;同时检查 error log 中有无 using uninitialized variable 提示——若有,说明 map 变量未正确继承或引用了非法上下文变量。
这种写法不改变业务逻辑,只优化执行路径,对高并发站点尤其有效。











