Nginx 的 set 指令用于在 server 或 location 块中定义请求级局部变量,仅当前请求有效,必须先声明后使用,值可为字符串、内置变量或正则捕获组,但不能在 rewrite 指令行内使用,且 if 中的 set 存在作用域限制;推荐用 map 替代 if+set 实现高效安全的条件映射。

Nginx 的 set 指令可以在 rewrite 过程中定义临时变量,但需注意它**不能直接在 if 块或 rewrite 指令内部使用**,而应放在 server 或 location 块顶层(或 if 内部)提前声明,再在后续 rewrite 中引用。
set 指令的基本用法和作用域限制
set 用于创建一个 NGINX 变量(以 $ 开头),值可以是字符串、其他变量、正则捕获组或内置变量。该变量仅在当前请求生命周期内有效,且只在当前作用域(如某个 location)及其子上下文中可用。
关键限制:
-
set不能出现在rewrite指令行里(语法错误) -
set在if块中定义时,只在该if分支内有效(NGINX 官方不推荐在if中大量使用set,因存在作用域陷阱) - 变量必须先定义后使用;未定义变量默认为空字符串,不会报错但可能导致重写逻辑异常
在 rewrite 前用 set 预设动态值
常见场景:根据 Host、URI 或请求头拼接目标路径。例如,把所有请求统一加前缀 /v1,但对特定域名跳过:
server {
listen 80;
server_name api.example.com internal.example.com;
<pre class="brush:php;toolbar:false;"># 根据 host 设置标志变量
set $version_prefix "";
if ($host = "api.example.com") {
set $version_prefix "/v1";
}
location / {
# 使用预设的 $version_prefix 参与 rewrite
rewrite ^(.*)$ $version_prefix$1 break;
}}
说明:这里 $version_prefix 在 if 中被赋值,随后在 rewrite 中拼接到原始 URI。注意 break 表示内部重写,不发起新请求。
结合正则捕获与 set 实现条件化重写
当需要从 URI 提取参数并参与后续判断时,可先用 set 保存捕获结果:
location /old/ {
# 捕获旧路径中的模块名,存入变量
if ($request_uri ~ ^/old/([^/]+)/) {
set $module_name $1;
}
<pre class="brush:php;toolbar:false;"># 根据 module_name 跳转到不同新路径
if ($module_name = "user") {
rewrite ^/old/user/(.*)$ /api/v2/users/$1? permanent;
}
if ($module_name = "order") {
rewrite ^/old/order/(.*)$ /api/v2/orders/$1? permanent;
}}
⚠️ 注意:上述写法依赖 if + set,虽可行但属于 NGINX “不推荐但支持” 的模式。更健壮的方式是用 map 指令做映射(见下一条)。
推荐替代方案:用 map 替代 if + set 做变量映射
map 是更高效、更安全的变量生成方式,适合静态或简单规则映射,且在配置加载时编译,性能优于运行时 if:
map $host $api_prefix {
default "";
"api.example.com" "/v1";
}
<p>map $uri $new_path {
~^/old/user/(.<em>) /api/v2/users/$1;
~^/old/order/(.</em>) /api/v2/orders/$1;
default $uri;
}</p><p>server {
location /old/ {
rewrite ^(.*)$ $new_path? permanent;
}
}</p>
这样既避免了 if 嵌套问题,又让变量逻辑清晰可维护,还支持缓存优化。











