一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Nginx 中 Rewrite 规则如何使用 set 指令在重写过程中自定义临时变量

时间:2026-08-23 20:03:48 编辑:袖梨 来源:一聚教程网

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

Nginx 的 set 指令可以在 rewrite 过程中定义临时变量,但需注意它不能直接在 if 块或 rewrite 指令内部使用,而应放在 serverlocation 块顶层(或 if 内部)提前声明,再在后续 rewrite 中引用。

set 指令的基本用法和作用域限制

set 用于创建一个 NGINX 变量(以 $ 开头),值可以是字符串、其他变量、正则捕获组或内置变量。该变量仅在当前请求生命周期内有效,且只在当前作用域(如某个 location)及其子上下文中可用。

关键限制:

  1. set 不能出现在 rewrite 指令行里(语法错误)
  2. setif 块中定义时,只在该 if 分支内有效(NGINX 最新不推荐在 if 中大量使用 set,因存在作用域陷阱)
  3. 变量必须先定义后使用;未定义变量默认为空字符串,不会报错但可能导致重写逻辑异常

在 rewrite 前用 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_prefixif 中被赋值,随后在 rewrite 中拼接到原始 URI。注意 break 表示内部重写,不发起新请求。

结合正则捕获与 set 实现条件化重写

当需要从 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 + set 做变量映射

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 嵌套问题,又让变量逻辑清晰可维护,还支持缓存优化。

热门栏目