1) map 指令是由 'ngx_http_map_module 模块'提供的,'默认'情况下nginx 会'安装'该模块
2) map 的主要作用是'创建自定义变量',通过使用 nginx 的'内置'变量,去'匹配'某些特定规则;
备注:只有'result_var'引用的时候,才会寻找这个'map'
(1)总述
说明: string["已有变量"]可以是'变量(动态提供了无限可能)',也可以是'字符串'
意外之喜: map的'源变量'可以是'组合形式'
map '${var1}${var2}' $result {
...
}
对比:if'只能'使用'某一个变量'判断① 理解新变量的值取决于多个源变量场景
细节: '源变量'必须是'已经存在的',不然'怎么做'适配
源变量: 即 map指令 后面的'那个string(已有变量)'

② map块何时被执行

map性能问题

(2)源值的形式

① 源值是裸字符串,不包含特殊字符串
源值如果是'裸字符串',则'不区分'大小写

② 源值是裸值,包含特殊字符

③ 源值以~和~*开头,只做正则表达式匹配
说明:最经常遇到的就是'正则域名'中需要'\.'转义
④ 源值以~和~*开头,正则表达式匹配后补获
说明: 这种方式,一次创建'多个'变量
1)方式1


2)方式2 重点掌握


(3) 结果值形式
高级: 结果值是'$uri'形式



(4)特殊参数
① default value


map $source_var target_var {
case "1";
default "";
}
+++++++ "等价形式" +++++++
map $source_var target_var {
case "1";
}② hostnames指令
应用场景: $http_host、$host变量
1)案例


2)优先级小结




细节点: 注意include'文件'的形式和'相对路径'


④ volatile


应用场景
++++++++++++ 'map的应用场景' ++++++++++++
1) 想象'编程语言'中的'switch { case: }'场景
2) 或者if {} else if {} else {}场景,这里都可以'转换'为map
3) map与'nginx log_format if=' 做'debug'判断
4) iframe嵌套,通过'map $http_referer $result'判断,另外通过改变'$result'做'例外'判断
5) nginx配置解决'低版本 Chrome浏览器'SameSite跨域'兼容性'问题
源变量必须是'已有变量'
强调:和'内置变量'才能玩出'花样'
说明:'string'一般我们会用'nginx的内置变量'来代替,不会直接写'裸值',便于'动态'
补充:已知'set、map、正则命名补获(?<name>.*)'三种方式来'设置变量'
关注点:chrome的'版本'跟SameSite的关系 --> 'Chrome/81.0.4044.138'nginx配置解决Chrome浏览器SameSite跨域问题 Chrome同站策略
nginx 为chrome客户端请求加SameSite=None;Secure
二 案例讲解
① 简单案例
map $args $foo {
default 0;
debug 1;
}
变量解读:$args 是nginx'内置[inner]'变量,$foo是我们自定义的'普通[common]'变量
附加:$args 这个变量等于'请求行中(GET请求)的参数',例如foo=123&bar=wzj;
效果:如果 $args '匹配到 debug' 那么 $foo 的值会'被设为 1 '
ps: 如果 $args 一个都'匹配不到' $foo 就是'default 定义的值',在这里就是 0
大白话:类似于一个'if/else'判断,设置'变量值'② 案例一:nginx开启websocket代理功能
http {
...
# 是否是'websocket'
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location /v1/kind {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# proxy_set_header Connection "upgrade"; -->对比二者的区别?
...
}
}websocket协议为什么HTTP Upgrade的时候需要Connection: upgrade ?
WebSocket为什么需要Connection和Upgrade两个header?
③ 案例二:后端代理切不同的版本、或者兰绿发布
upstream upstream_k8s {
server ip:port;
...
}
upstream upstream_default {
server ip:port
}
# zone是存储区域
limit_req_zone $client_real_ip zone=A:100m rate=1000r/s
limit_conn_zone $client_real_ip zone=B:100m;
# 变量必须是nginx的内置变量吗? -->'非必须'
map $COOKIE_k8s_flag $k8s {
# 等待匹配的字符串可以不加引号
k8s1 upstream_k8s;
# 说明:upstream_default和upstream_k8s与前面的映射
deafult upstream_default;
}
location /k8s {
limit_req zone=A burst=10000 nodelay;
limit_conn B 1000;
# 注意引入方式
proxy_pass https://${k8s};
...
}④ 案例三:跨域名访问
# 这些配置可以写在 http{} 或者 server{} 都是'支持'的
add_header Access-Control-Allow-Origin "http://www.wzj.com";
add_header Access-Control-Allow-Methods "POST, GET, PUT, OPTIONS, DELETE";
add_header Access-Control-Max-Age "3600";
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept";
1) 上面的配置'只允许' http://www.wzj.com 跨域访问
2) 如果要支持'所有域名'都可以跨域调用该站, 不过'不推荐'这样做,因为'不安全'
add_header Access-Control-Allow-Origin "*";
++++++++++++++"不想允许所有,但是又需要允许多个域名,那么就需要用到 map"++++++++++++++
需求: 使用 map 来实现允许'多个域名跨域'访问的问题
map $http_origin $corsHost {
default 0;
"~http://www.wzj.com" http://www.wzj.com;
"~http://" http://harbor.wzj.com;
"~http://nginx.wzj.com" http://nginx.wzj.com;
}
server{
listen 80;
server_name www.wzj.com;
root /nginx;
location /
{
add_header Access-Control-Allow-Origin $corsHost;
...
}
}⑤ map相关调试
需求:使用源变量'通常是 nginx 内置变量'匹配一些规则,创建自定义变量,然后在页面输出. 这通常在'调试'的时候非常有用
复制代码
http {
map $uri $match {
# 说明:default可以'省略'
~^/www/(.*) http://www.wzj.com/;
}
server {
listen 8080;
server_name harbor.wzj.com;
location /www {
default_type text/plain;
echo uri: $uri;
echo match: $match;
echo capture: $1;
echo new: $match$1;
}
细节:openresty自带'echo'模块⑥ map指令的阶段问题

⑦ 典型的应用场景
+++++++++++++++++ "后续再遇到"会慢慢补充 +++++++++++++++++
1) 特殊'版本'的agent才允许访问
2)nginx自身通过XFF获取'真实ip' -->创建其它'新变量'
3) 'websocket'配置
4)跨域
















