震驚--Nginx的map指令還能這樣用

發表於2022-05-08

map指令簡單介紹

當然這裡寫的都是官方文件是已經寫過的,我簡單抄一下哈。

map指令來自於 ngx_http_map_module 模組,提供的核心能力是 基於一個變數建立一個新變數,大概是這意思。

語法: 只能配置在http塊內
map string $variable {...}

直接看這個語法好像看不出來它能幹什麼,所以官方文件上給了幾個例子:

map $http_host $name {
    hostnames;

    default       0;

    example.com   1;
    *.example.com 1;
    example.org   2;
    *.example.org 2;
    .example.net  3;
    wap.*         4;
}

解析一下上面?這個例子的意思?:

map: 關鍵字,開闢一段記憶體空間宣告一個map

$http_host: 獲取host請求頭:eg: www.baidu.com

$name: 新變數,具體取值是什麼取決於結構體內的對映關係

結構體內的資料解析:
    hostnames:
    - 官方文件給出的解釋是:允許用字首或者字尾掩碼指定域名作為源變數值。這個引數必須寫在值對映列表的最前面。

    讀都能讀的懂,字也都認識,但是怎麼感覺好像還是不太懂呢,又沒有同感?於是我測試了一下,其實就是你想用下面那種泛域名來匹配host的話就加一下這個引數, 否則是達不到預期效果的。

    default 0; :匹配不到符合條件的資料時 則$name 這個變數就取預設值 0

知道了這之後我能用它來做什麼呢?看實際應用的例子

map指令的實踐使用

1. 基於cookie做多環境分流

一般中大型公司都會有多套測試環境,對於多環境的訪問可能最容易想到的就是對應多個域名,這方法當然可以,但是不優雅,維護多個域名太累。為了偷懶,我們用了一個域名,使用不同的cookie來轉發相應的流量到相應的環境。

如何實現?

    map $cookie_cl_env_num $cl_backend_map {
        default   1.1.1.1:80;
        dev-01    upstream_dev-01;
        dev-02    upstream_dev-02;
        dev-03    upstream_dev-03;
        test-01   upstream_test-01;
        test-02   upstream_test-02;
        test-03   upstream_test-03;
        test-04   upstream_test-04;
        test-05   upstream_test-05;
        test-06   upstream_test-06;
        test-07   upstream_test-07;
        test-08   upstream_test-08;
        test-09   upstream_test-09;
        test-10   upstream_test-10;
        test-11   upstream_test-11;
        test-12   upstream_test-12;
        test-13   upstream_test-13;
        test-14   upstream_test-14;
        test-15   upstream_test-15;
    }

    # 隨便寫一個
    upstream upstream_test-14 {
        server 2.2.2.2:80;
    }

    # 區域性實現寫一下
    location / {
        pass_pass http://$cl_backend_map;
    }

    # 請求
    curl --cookie "cl_env_num=test-15" a.test.com/api/v1/hahaha

這不就實現了嘛,很方便哈。僅提供思路!當然也可以使用其他變數來分流 UA|args ...

2. 做安全的多域名跨域訪問

跨域訪問一般情況下我們都會直接設定 * 允許所有跨域訪問。但是難免會有一些對安全性要求較高的業務不允許這樣,那麼對於域名比較多的安全跨域配置,也可以使用map來實現。

map $http_origin $allow_origin {
    ~http://www.baidu.com http://www.baidu.com;
    ~http://m.baidu.com   http://m.baidu.com;
    ~http://a.baidu.com   http://a.baidu.com;
    default               deny;
}

server {
    listen 80;
    server_name www.baidu.com;

    location / {
        ...
        add_header Access-Control-Allow-Origin $allow_origin;
        ...
    }
}

僅提供思路哈,具體情況可以再優化

總結

當然還有很多場景都可以用到, 無法一一列舉, 自己能夠根據需求和場景靈活運用是最好的。

相關文章