Map 介绍

map 指令是 Nginx 装备文件中的一个指令,它用于在恳求处理期间创立变量,并依据指定的键值对映射联系进行值的映射。它能够用于动态地生成装备项的值,例如依据恳求的 URL、恳求头、查询参数等信息来生成不同的值。

map 指令的语法如下:

map$variable$new_variable{
keyvalue;
keyvalue;
...
defaultvalue;
}

其间,variable是要映射的变量,可所以任何有效的Nginx变量,如variable 是要映射的变量,可所以任何有效的 Nginx 变量,如 uri、args、args、http_host 等;$new_variable 是映射后的新变量名,能够自定义;key 是映射的键,可所以字符串、正则表达式或许变量;value 是映射的值,可所以字符串、变量或许表达式;default 是默许值,当没有匹配到任何键时运用。

map 指令的作用是将 variable的值依据键值对映射联系映射到variable 的值依据键值对映射联系映射到 new_variable 上,并且这个映射是在装备文件加载时进行的,不会在恳求处理期间进行计算。一旦映射联系确认,映射的值会保存在 $new_variable 中,并能够在装备文件中的其他地方运用。

map 指令能够用于许多场景,例如依据恳求的途径生成重写规则、依据恳求头判断是否启用缓存、依据查询参数装备不同的后端服务等。它为 Nginx 供给了更加灵活和动态的装备选项。下面看几个经典运用场景。

巧用map实现Nginx stream依据源IP做路由负载

业务方新加了一个业务网关,上线前需要做个验证,把来历ip为27.38.x.255和116.30.x.170拜访用户路由到新new_gateway做验证,其他的持续走old_gateway。


stream{

log_formatbasic'$time_iso8601$remote_addr'
'$protocol$status$bytes_sent$bytes_received'
'$session_time$upstream_addr'
'"$upstream_bytes_sent""$upstream_bytes_received""$upstream_connect_time"';
access_log/var/log/nginx/stream.logbasicbuffer=1kflush=5s;
upstreamold_gateway{
server10.6.11.86:8080;
}
upstreamnew_gateway{
server10.6.11.86:80;
}
map$remote_addr$backend_svr{
"27.38.x.255""new_gateway";
"116.30.x.170""new_gateway";
default"old_gateway";
}

server{
listen8080;
proxy_connect_timeout2s;
#ssl_prereadon;
#proxy_protocolon;
proxy_pass$backend_svr;
}
}

要依据Nginx变量($cookie_uin)约束恳求数

现在有个uri(/v3/aggregate/broker/trade/NewIpoFinancing)要依据Nginx变量($cookie_uin)约束恳求数.

1 约束每个uin 2s一个恳求,如果$cookie_uin 为空,则给一个默许的uin

//在Nginx主装备文件增加如下装备
http{
includemime.types;
...
map$cookie_uin$my_cookie_uin{
default$cookie_uin;
'-'10010;
''10010;
}
limit_req_zone$my_cookie_uinzone=limit_per_uin:10mrate=30r/m;

...

}
//uri接口装备文档
location~^/v3/aggregate/broker/trade/NewIpoFinancing{
limit_reqzone=limit_per_uinburst=3nodelay;
include/etc/nginx/vhost/common/cors.conf;
proxy_passhttp://access_trade3;
}

2 约束每个uin 2s一个恳求,如果$cookie_uin 为空,返回403

//在Nginx主装备文件增加如下装备
http{
includemime.types;
...
map$cookie_uin$limit_key{
default0;
'-'1;
''1;
}
limit_req_zone$cookie_uinzone=limit_per_uin:10mrate=30r/m;

...

}
//uri接口装备文档
location~^/v3/aggregate/broker/trade/NewIpoFinancing{
if($limit_key=1){
return403;
}
limit_reqzone=limit_per_uinburst=3nodelay;
include/etc/nginx/vhost/common/cors.conf;
proxy_passhttp://access_trade3;
}

3 约束每个uin 2s一个恳求,如果$cookie_uin 为空,返回403, 如果是vip uin不做约束

//在Nginx主装备文件增加如下装备
http{
includemime.types;
...
map$cookie_uin$limit_key{
default0;
'-'1;
''1;
'666666'10;
'666667'10;
'666668'10;
}
limit_req_zone$cookie_uinzone=limit_per_uin:10mrate=30r/m;
...

}
//uri接口装备文档
location~^/v3/aggregate/broker/trade/NewIpoFinancing{
if($limit_key=1){
return403;
}
#vipuin
error_page410=@nolimit;
if($limit_key=10){
return410;
}
limit_reqzone=limit_per_uinburst=3nodelay;
include/etc/nginx/vhost/common/cors.conf;
proxy_passhttp://access_trade3;
}
location@nolimit{
include/etc/nginx/vhost/common/cors.conf;
proxy_passhttp://access_trade3;
}

使用Nginx Map实现正向署理动态切换

map$host$idc{
defaultlg;
}

map$idc$backend_4430_svr{
defaulthttps://$host$request_uri;
lghttps://$host$request_uri;
kxhttp://10.0.x.136:4430;
}

map$idc$backend_8880_svr{
defaulthttp://$host$request_uri;
lghttp://$host$request_uri;
kxhttp://10.0.x.13:8880;
}

map$idc$backend_4480_svr{
default$http_PROT://$http_DN:$http_Port;
lg$http_PROT://$http_DN:$http_Port;
kxhttp://10.0.x.13:4480;
}

server{
listen8880;
location/{
resolver127.0.0.1;
proxy_pass$backend_8880_svr;
proxy_set_headerHost$host;
proxy_set_headerX-Real-IP$remote_addr;
proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
}
}

server{
listen4480;
location/{
resolver127.0.0.1;
proxy_pass$backend_4480_svr;
proxy_set_headerHost$http_DN;
proxy_connect_timeout10s;
proxy_read_timeout20s;
}
}
server{
listen4430;
location/{
resolver127.0.0.1;
proxy_pass$backend_4430_svr;
proxy_set_headerHost$host;
proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;
}
}

依据恳求头中的PROT、DN和Port字段的值,将恳求转发到不同的后端服务器。其间,PROT字段表示恳求的协议(http或https),DN字段表示恳求的域名,Port字段表示恳求的端口号。

依据装备文件中的map指令,将host(恳求头中的域名)映射为host(恳求头中的域名)映射为idc,然后依据$idc的值将恳求转发到相应的后端服务器。

详细的转发规则如下:

idc的值为ns时,将恳求转发到idc的值为ns时,将恳求转发到backend_4430_svr,并将恳求头中的Host字段和X-Forwarded-For字段传递给后端服务器。

idc的值为ft时,将恳求转发到idc的值为ft时,将恳求转发到backend_8880_svr,并将恳求头中的Host字段、X-Real-IP字段和X-Forwarded-For字段传递给后端服务器。

idc的值为其他值时,将恳求转发到idc的值为其他值时,将恳求转发到backend_4480_svr,并将恳求头中的Host字段、PROT字段、DN字段和Port字段传递给后端服务器。

恳求的详细转发地址是依据装备文件中的map指令和后端服务器的装备进行拼接的,例如https://hosthostrequest_uri表示将恳求转发到https协议下的当前域名,并保留原始恳求的URI途径。

因此,当运用以下命令发送恳求时:


curl-v-H'content-type:aplication/json'-H'PROT:https'-H'DN:www.test.com'-H'Port:8899'-d'{"data":"xxxx","body":"1"}'http://nginx_ip:4480/test/uri

恳求将被转发到$backend_4480_svr,并依据恳求头中的PROT、DN和Port字段的值拼接成后端服务器的地址,同时将恳求头中的Host字段、PROT字段、DN字段和Port字段传递给后端服务器。详细的转发地址会依据装备文件中的map指令和后端服务器的装备进行动态生成。