Nginx功能篇17—映射

概述

本章,您将了解到 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 大括号内的搜索满足匹配成功即停止,其匹配的先后顺序如下:

    1. 不带掩码的字符串 - 精准匹配,这里的掩码即 * 符号
    2. 最长的带前缀掩码的字符串 - 如 *.example.com
    3. 最长的带后缀掩码的字符串 - 如 mail.*
    4. 正则表达式 - 按照匹配文件中的出现顺序,第一个‌匹配的正则生效。其中 ~ 表示区分大小写的正则;~* 表示不区分大小写的正则
    5. 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
Avatar photo

关于 陸風睿

GNU/Linux 从业者、开源爱好者、技术钻研者,撰写文档既是兴趣也是工作内容之一。Q - "281957576";WeChat - "jiulongxiaotianci",Github - https://github.com/jimcat8
用一杯咖啡支持我们,我们的每一篇[文档]都经过实际操作和精心打磨,而不是简单地从网上复制粘贴。期间投入了大量心血,只为能够真正帮助到您。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇