Map 介绍
map 指令是 Nginx 配置文件中的一个指令,它用于在请求处理期间创建变量,并根据指定的键值对映射关系进行值的映射。它可以用于动态地生成配置项的值,例如根据请求的 URL、请求头、查询参数等信息来生成不同的值。
map 指令的语法如下:
map $variable $new_variable {
key value;
key value;
...
default value;
}
复制代码
其中,variable是要映射的变量,可以是任何有效的Nginx变量,如uri、args、http_host 等;$new_variable 是映射后的新变量名,可以自定义;key 是映射的键,可以是字符串、正则表达式或者变量;value 是映射的值,可以是字符串、变量或者表达式;default 是默认值,当没有匹配到任何键时使用。
map 指令的作用是将 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_format basic '$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.log basic buffer=1k flush=5s;
upstream old_gateway {
server 10.6.11.86:8080;
}
upstream new_gateway {
server 10.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 {
listen 8080;
proxy_connect_timeout 2s;
#ssl_preread on;
#proxy_protocol on;
proxy_pass $backend_svr;
}
}
复制代码
要基于 Nginx 变量($cookie_uin)限制请求数
现在有个 uri(/v3/aggregate/broker/trade/NewIpoFinancing)要基于 Nginx 变量($cookie_uin)限制请求数.
1 限制每个 uin 2s 一个请求,如果 $cookie_uin 为空,则给一个默认的 uin
//在Nginx主配置文件添加如下配置
http {
include mime.types;
...
map $cookie_uin $my_cookie_uin {
default $cookie_uin;
'-' 10010;
'' 10010;
}
limit_req_zone $my_cookie_uin zone=limit_per_uin:10m rate=30r/m;
...
}
// uri 接口配置文档
location ~ ^/v3/aggregate/broker/trade/NewIpoFinancing {
limit_req zone=limit_per_uin burst=3 nodelay;
include /etc/nginx/vhost/common/cors.conf;
proxy_pass http://access_trade3;
}
复制代码
2 限制每个 uin 2s 一个请求,如果 $cookie_uin 为空,返回 403
//在Nginx主配置文件添加如下配置
http {
include mime.types;
...
map $cookie_uin $limit_key {
default 0;
'-' 1;
'' 1;
}
limit_req_zone $cookie_uin zone=limit_per_uin:10m rate=30r/m;
...
}
// uri 接口配置文档
location ~ ^/v3/aggregate/broker/trade/NewIpoFinancing {
if ($limit_key = 1) {
return 403;
}
limit_req zone=limit_per_uin burst=3 nodelay;
include /etc/nginx/vhost/common/cors.conf;
proxy_pass http://access_trade3;
}
复制代码
3 限制每个 uin 2s 一个请求,如果 $cookie_uin 为空,返回 403, 如果是 vip uin 不做限制
//在Nginx主配置文件添加如下配置
http {
include mime.types;
...
map $cookie_uin $limit_key {
default 0;
'-' 1;
'' 1;
'666666' 10;
'666667' 10;
'666668' 10;
}
limit_req_zone $cookie_uin zone=limit_per_uin:10m rate=30r/m;
...
}
// uri 接口配置文档
location ~ ^/v3/aggregate/broker/trade/NewIpoFinancing {
if ($limit_key = 1) {
return 403;
}
#vip uin
error_page 410 = @nolimit;
if ($limit_key = 10) {
return 410;
}
limit_req zone=limit_per_uin burst=3 nodelay;
include /etc/nginx/vhost/common/cors.conf;
proxy_pass http://access_trade3;
}
location @nolimit {
include /etc/nginx/vhost/common/cors.conf;
proxy_pass http://access_trade3;
}
复制代码
利用 Nginx Map 实现正向代理动态切换
map $host $idc {
default lg;
}
map $idc $backend_4430_svr {
default https://$host$request_uri;
lg https://$host$request_uri;
kx http://10.0.x.136:4430;
}
map $idc $backend_8880_svr {
default http://$host$request_uri;
lg http://$host$request_uri;
kx http://10.0.x.13:8880;
}
map $idc $backend_4480_svr {
default $http_PROT://$http_DN:$http_Port;
lg $http_PROT://$http_DN:$http_Port;
kx http://10.0.x.13:4480;
}
server {
listen 8880;
location / {
resolver 127.0.0.1;
proxy_pass $backend_8880_svr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 4480;
location / {
resolver 127.0.0.1;
proxy_pass $backend_4480_svr;
proxy_set_header Host $http_DN;
proxy_connect_timeout 10s;
proxy_read_timeout 20s;
}
}
server {
listen 4430;
location / {
resolver 127.0.0.1;
proxy_pass $backend_4430_svr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
复制代码
根据请求头中的 PROT、DN 和 Port 字段的值,将请求转发到不同的后端服务器。其中,PROT 字段表示请求的协议(http 或 https),DN 字段表示请求的域名,Port 字段表示请求的端口号。
根据配置文件中的 map 指令,将host(请求头中的域名)映射为idc,然后根据 $idc 的值将请求转发到相应的后端服务器。
具体的转发规则如下:
当idc的值为ns时,将请求转发到backend_4430_svr,并将请求头中的 Host 字段和 X-Forwarded-For 字段传递给后端服务器。
当idc的值为ft时,将请求转发到backend_8880_svr,并将请求头中的 Host 字段、X-Real-IP 字段和 X-Forwarded-For 字段传递给后端服务器。
当idc的值为其他值时,将请求转发到backend_4480_svr,并将请求头中的 Host 字段、PROT 字段、DN 字段和 Port 字段传递给后端服务器。
请求的具体转发地址是根据配置文件中的 map 指令和后端服务器的配置进行拼接的,例如 https://hostrequest_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 指令和后端服务器的配置进行动态生成。
评论