概述
本章,您将了解到 Nginx 配置文件中的映射。
映射:在 Nginx 中,映射指的是根据当前的变量值动态地去设置另外一个变量的值。使用映射后,可以更加灵活地处理复杂的请求逻辑,而无需冗长的条件判断。
map 指令
语法为 map string $variable { ... },只能配置在 http 上下文中。
基本语法的示例:
...
http {
...
map $my_var_check $new_var {
key1 value1;
key2 value2;
key3 value3; # 三个键值对
~regex value4; # 正则表达式
default default_value; # 没有匹配项时使用的默认值
}
server {
...
location / {
...
}
}
}
说明如下:
$my_var_check- 要检查的内置变量,在 Nginx 文档中被称为源变量$new_var- 目标变量,即新生成的自定义变量,可在后续配置中进行引用default- 关键字-
map大括号内的搜索满足匹配成功即停止,其匹配的先后顺序如下:- 不带掩码的字符串 - 精准匹配,这里的掩码即
*符号 - 最长的带前缀掩码的字符串 - 如
*.example.com - 最长的带后缀掩码的字符串 - 如
mail.* - 正则表达式 - 按照匹配文件中的出现顺序,第一个匹配的正则生效。其中
~表示区分大小写的正则;~*表示不区分大小写的正则 default- 所有都不匹配时进行兜底
- 不带掩码的字符串 - 精准匹配,这里的掩码即
提示
map 指令只定义了映射规则,其并不会主动生效,只有当配置中引用了 map 指令的目标变量时,映射才会被计算并生效。
常见使用场景
场景一:根据 Host 做逻辑分流
...
http {
...
map $http_host $backend {
default 192.168.100.20:9000;
www.games.com 192.168.100.20:9001;
api.games.com 192.168.100.20:9002;
}
server {
listen 192.168.100.10:80;
server_name games.com www.games.com api.games.com;
...
location / {
proxy_pass http://$backend;
}
}
}
$http_host - 对应客户端请求头中的 Host 字段,虽然在官方文档的 内置变量列表 中并没有提及。以 $http_ 开头的都表示客户端请求头中的变量,这在官方文档页面的 Embedded Variables 位置有说明:
$http_name
arbitrary request header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
拆解说明:
- 当用户访问 http://www.games.com/api 时,浏览器发送
Host: www.games.com,此时$http_host = "www.games.com" - Nginx 读取
Host: www.games.com,通过map指令中的匹配先后顺序,为变量$backend赋值为192.168.100.20:9001 - 在
location / { ...}中通过 proxy_pass http://$backend 引用该变量,映射实际生效
场景二:根据 UA 标识判断客户端类型
...
http {
...
map $http_user_agent $client_type {
default "unknown";
~*mobile "mobile"; # 不区分大小写,匹配包含 mobile 的 UA
~*android "mobile"; # 匹配 Android
~*iphone "mobile"; # 匹配 iPhone
~*ipad "tablet"; # 匹配 iPad
~*tablet "tablet"; # 匹配其他平板
~*windows "desktop"; # 匹配 Windows 桌面
~*macintosh "desktop"; # 匹配 macOS 桌面
}
server {
listen 192.168.100.10:80;
server_name games.com www.games.com;
...
location / {
# X-Client-Type 是随便自定义的一个响应头
add_header X-Client-Type $client_type;
# 根据类型返回不同页面
if ($client_type = "mobile") {
root /var/www/html/mobile;
}
if ($client_type = "desktop") {
root /var/www/html/desktop;
}
# 默认(unknown/tablet)走通用目录
if ($client_type = "unknown") {
root /var/www/html/default;
}
}
}
}
说明:
- 当 iphone 访问 http://www.games.com 时,会发送
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X)...这样的信息,其中 $http_user_agent 包含 iPhone 字符串 - Nginx 读取客户端的请求头信息,按照
map指令中定义的先后匹配,命中~*iphone,为变量$client_type赋值为"mobile" - 在 location 上下文中添加自定义的响应头并给定参数值,通过 if 条件判断来适配不同的客户端
场景三:URI 重定向
由于历史原因或技术更替或其他原因,需要将旧的 URI 重定向到新 URI。
...
http {
...
map $request_uri $new_uri {
~^/api(/|$) /new-api$1;
~^/backup(/|$) /new-backup$1;
~^/news(/|$) /new-news$1;
default "";
}
server {
listen 192.168.100.10:80;
server_name games.com www.games.com api.games.com;
...
location / {
if ($new_uri) {
return 301 $new_uri;
}
}
}
}
^在正则表达式中表示匹配开头()在正则表达式中表示组合匹配|在正则表达式中表示或的意思$1在正则表达式中表示引用第一个捕获组(第一个括号中的内容)
实际匹配效果:
| 请求 URI | 捕获组 () 匹配到 | $1 的值 | $new_uri 结果 |
|---|---|---|---|
/api |
行尾符($) | 空字符串("") | /new-api |
/api/ |
/ |
"/" | /new-api/ |
/api/user |
/ |
"/" | /api/user |
版权声明:「自由转载-保持署名-非商业性使用-禁止演绎 3.0 国际」(CC BY-NC-ND 3.0)
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论









