用 nginx map 做多条件跳转
发布时间:2025-12-20 13:23       
更新时间:2025-12-21 07:43
Nginx 的 map 指令干"按条件选值"的活:定义一张映射表,输入一个变量,按表返回另一个值。多条件跳转用它来写,比堆一串 if 干净得多,条件集中在一张表里,一眼看完。
语法与位置
map 只能写在 http 块里,放 server 块内会直接报语法错误。基本形态:
map $host $is_old {
default 0;
old-a.example.com 1;
old-b.example.com 1;
}
左边是输入变量的取值,右边是返回值,default 兜底必写,漏了未匹配请求会拿到空值,空值在跳转场景里的表现千奇百怪,极难排查,务必写上 default。匹配优先级是精确值先于正则;域名匹配默认不区分大小写,想区分用 hostnames 参数另有讲究,常规场景用不到,拿不准就照本文示例写。
示例一:多个旧域名统一跳新域
server {
listen 80;
if ($is_old) {
return 301 https://www.example.com$request_uri;
}
}
以后新增旧域名,只需要往 map 里加一行,server 块完全不动,这就是 map 相对多个 if 的核心优势,映射表越大优势越明显。输入键还能拼接组合,比如 map "$scheme://$host" $target 可以把协议和域名放在一起判断,http 和 https 各走各的映射,组合键用什么分隔符自己定,保证不产生歧义即可。
示例二:按域名分流到不同后端
upstream web_main { server 127.0.0.1:8081; }
upstream web_api { server 127.0.0.1:8082; }
map $host $backend {
default web_main;
api.example.com web_api;
}
location / {
proxy_pass http://$backend;
}
API 域名指到独立后端,其余走默认,灰度分组、新老版本并存都能套这个模式,上线前把每个分支都请求一遍,避免某些取值落进 default 而没被发现。返回值用 upstream 名最稳,直接写 IP 加端口(127.0.0.1:8082)也能用,但失去 upstream 里的权重、健康检查这些能力,正式环境建议前者。
维护提醒
映射表长了以后单独存一个文件,用 include 引进 http 块,每行注释写清用途;改完 nginx -t 通过再 reload,拿不准 include 有没有生效,用 nginx -T 输出全量配置来核对,输出里会带配置来源路径,正好定位映射表文件。值里要用正则时以 ~ 开头,别和普通字符串混着写;同一张表里精确值和正则并存时,精确值永远先匹配,把兜底交给 default,不要依赖书写顺序,顺序依赖是配置里最脆弱的东西。