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