nginx(二十四)map指令

一    ngx_http_map_module模块

1) map 指令是由 'ngx_http_map_module 模块'提供的,'默认'情况下nginx 会'安装'该模块

2) map 的主要作用是'创建自定义变量',通过使用 nginx 的'内置'变量,去'匹配'某些特定规则;

备注:只有'result_var'引用的时候,才会寻找这个'map' 

(1)总述

说明: string["已有变量"]可以是'变量(动态提供了无限可能)',也可以是'字符串'

意外之喜: map的'源变量'可以是'组合形式'

map '${var1}${var2}'  $result {
  ... 
}

对比:if'只能'使用'某一个变量'判断

灵活应用 nginx map

①  理解新变量的值取决于多个源变量场景

细节: '源变量'必须是'已经存在的',不然'怎么做'适配

源变量: 即 map指令 后面的'那个string(已有变量)'

②   map块何时被执行

map性能问题

(2)源值的形式

①  源值裸字符串,不包含特殊字符串

源值如果是'裸字符串',则'不区分'大小写

②  源值是,包含特殊字符

③  源值以~~*开头,只做正则表达式匹配

说明:最经常遇到的就是'正则域名'中需要'\.'转义

④  源值以~~*开头,正则表达式匹配后补获

说明: 这种方式,一次创建'多个'变量

 nginx的命名补获 

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

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

④   volatile

 (5)应用场景

++++++++++++  '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>.*)'三种方式来'设置变量'

补充

二   案例讲解

1、所有的'案例场景'都是基于'变量',基于'请求处理过程'来说明

2、了解哪些'指令'可以使用'哪些变量'

备注: limit_req_zone  $variable

3、map 是'基于变量'才玩出花活

补充: '变量'与'dynamic'动态关联起来了,不用'reload'了

①    查询参数

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?

nginx支持websocket反向代理

③  灰度发布

说明; nginx 实现灰度发布的方式有'多种',大多是基于'请求信息 [uuid、ip、请求头]'等标示的

思考: nginx是否能基于'第三方平台'的响应信息,捕获'然后分析'做判断,继续下一步请求?

root指令    alias指令

1、前端: '兰绿 [灰度]'发布,切换不同的'版本'

技术点: root '指令的值'可以携带'变量'

推荐:  $http_gray 或 $http_fronted 这种'自定义'请求头

引申:  前端如何'全局'加自定义请求头

2、后端: '兰绿 [灰度]'发布,切换不同的'版本'

技术点: proxy_paas '指令的值'可以携带变量

推荐:  $COOKIE_k8s_flag 这种'大小写'结合的方式
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};
    ...
}

获取客户端的真实ip

背景: 我们知道'$remote_addr'是TCP'直连'的ip,'不是'客户端的真实ip

说明: 该案例尝试从'XFF'头中获取客户端的'真实ip',需要每层proxy代理'都透传'

++++++++++++++++  "本文只简单罗列关键配置"  ++++++++++++++++

map $http_x_forwarded_for $client_ip {
        default $remote_addr;
        ~^(?<first_ip>[^,]+),?.*$ $first_ip;
        # ~^(?:\d+.\d+.\d+.\d+)(?:,|$) $1;
}

map $client_ip $result {
        1 normal_upstream;
        # 验证白名单列表 --> 只允许这几个'特定ip的用户'来访问B版本
        1.1.1.1 gray_upstream;
        2.2.2.2 gray_upstream;
}

location /api {
     proxy_pass https://$result;
}

核心点: 通过'正则'获取到XFF头的第一个'ip'

④  跨域名访问

推荐: 把'CORS'抽离到cors.conf的配置'文件'中

# 这些配置可以写在 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://m.haibakeji.com" 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相关调试

需求:

   1)  使用源变量'通常是 nginx 内置变量'匹配一些规则,创建自定义变量

   2)  然后在页面输出. 这通常在'调试'的时候非常有用


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'模块 或者 nginx '源码编译'

map相关参考 

⑥  nginx通过map 删除 HttpOnly、Secure

# 删除Cookie中的HttpOnly
map $sent_http_set_cookie $remove_cookie {
    ~*(?<CK>.+)HttpOnly $CK;
}
    
server {
    listen 80;
    server_name  *.wzj.com;
    
    location / {
    
        add_header Set-Cookie $remove_cookie;
        
        proxy_pass  http://xxxxx;
   }
}

+++++++++++++++++++++++++ "拆解分析" +++++++++++++++++++++++++

1、按照Cookie规范,HttpOnly是'最后一个字符串'

2、通过在map中使用正则表达式提取'除HttpOnly之前'的值,然后使用'add_header'复写到Cookie中

3、$sent_http_set_cookie 为 nginx '预定义'内置变量,获取后端的'Set-Cookies'响应头

4、处理 Cookie 的 Secure 也'是一样'

本质: nginx拦截'Set-Cookie'响应头,对其进行'二次'加工

补充: 也可以通过'proxy_cookie_flags'来解决这里不再'赘述'了

proxy_cookie_flags

⑦  利用 $http_user_agent做不同客户端的适配

补充: '不同'客户端版本,同一客户端的'不同'版本

关注点:chrome的'版本'跟SameSite的关系 --> 'Chrome/81.0.4044.138'

nginx配置解决Chrome浏览器SameSite跨域问题     Chrome同站策略

nginx 为chrome客户端请求加SameSite=None;Secure

⑧  map指令的阶段问题

map 路径重写、请求分发、权限控制三种典型应用场景

⑨  典型的应用场景

+++++++++++++++++ "后续再遇到"会慢慢补充  +++++++++++++++++

1) 特殊'版本'的agent才允许访问

2)nginx自身通过XFF获取'真实ip' -->创建其它'新变量'

3) 'websocket'配置

4)CORS '跨域'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值