Nginx的map指令本身不控制访问,需结合if+return或proxy_pass实现灰度分流:先用map将IP、Header等映射为灰度标识变量(如$is_gray_user),再在location中基于该变量做路由、响应或Cookie打标,实现多维度精准灰度。

Nginx 的 map 指令本身不直接控制访问,但它能将请求特征(如 IP、Header、Cookie)映射为变量值,再配合 allow/deny 或 if + return 实现灵活的多维度灰度分流。关键在于:用 map 构建“灰度标识”,再在 location 或 server 块中基于该标识做决策。
1. 用 map 提取并标记灰度用户
比如同时依据「客户端真实 IP」和「请求头中的灰度标识」决定是否进入灰度环境:
http {
# 从 X-Real-IP 或 X-Forwarded-For 提取可信客户端 IP
map $http_x_real_ip $client_ip {
"" $remote_addr;
default $http_x_real_ip;
}
<pre class="brush:php;toolbar:false;"># 定义灰度 IP 段(支持 CIDR)
map $client_ip $is_gray_ip {
default 0;
~^192\.168\.10\. 1; # 192.168.10.0/24
~^10\.200\.50\. 1; # 10.200.50.0/24
}
# 读取业务侧传入的灰度开关(如 Header 或 Cookie)
map $http_x_gray_flag $is_gray_header {
"on" 1;
"true" 1;
default 0;
}
# 合并多个条件:IP 在灰度段 或 显式声明灰度
map "$is_gray_ip:$is_gray_header" $is_gray_user {
"1:0" 1;
"0:1" 1;
"1:1" 1;
default 0;
}}
注意:map 值必须是字符串,所以用冒号拼接再匹配;$is_gray_user 最终为 "1" 或 "0",可在后续逻辑中直接判断。
2. 在 location 中按灰度变量路由或拦截
不推荐直接用 allow/deny 配合 map 变量(Nginx 不支持变量用于 allow),而应使用 if + proxy_pass 或 return 分流:
- 方式一:灰度用户走新后端
upstream backend_prod {
server 10.0.1.100:8080;
}
<p>upstream backend_gray {
server 10.0.1.101:8080;
}</p><p>server {
location /api/ {
if ($is_gray_user = "1") {
proxy_pass <a href="https://www.php.cn/link/31602be755d508de28cf56c9eec6e9e4">https://www.php.cn/link/31602be755d508de28cf56c9eec6e9e4</a>;
break;
}
proxy_pass <a href="https://www.php.cn/link/76350336f8c9ed0cd84f23b6fafcefa7">https://www.php.cn/link/76350336f8c9ed0cd84f23b6fafcefa7</a>;
}
}</p>- 方式二:灰度用户返回特定响应(如降级提示或 mock 数据)
location /feature/new {
if ($is_gray_user = "1") {
return 200 '{"status":"gray","data":{...}}';
}
proxy_pass https://www.php.cn/link/76350336f8c9ed0cd84f23b6fafcefa7;
}3. 进阶:结合 Cookie 实现用户级长期灰度
让灰度用户首次命中后自动打标,后续请求靠 Cookie 维持状态:
}
这样即使 IP 变化,只要 Cookie 存在,仍维持灰度身份。注意避免重复 set-cookie,可用 if ($cookie_gray_uid = "") { ... } 控制。
4. 注意事项与避坑点
-
map块必须在http级别定义,不能放在server或location内 - 正则匹配 IP 时,
$client_ip必须已解析为真实地址(确保前置有set_real_ip_from和real_ip_header) -
if在location中是安全的,但在server级慎用(可能引发重写循环) - 不要用
if ($is_gray_user) { deny all; }——deny不接受变量,会报错 - 灰度规则变更后需 reload Nginx,无法热更新;高频变动建议交由上游服务(如 OpenResty Lua)处理











