理解 Nginx 在處理請求時的匹配規則

nginx 在收到一條請求時將先經過 server_name 匹配一個 server, 而後使用 server 中的 location 繼續匹配.html

匹配 server_name

nginx 中, server_name 決定了當收到一個請求後哪個 server 會被使用. nginx 會使用請求頭中的 Host 字段與 server_name 進行匹配. 定義 server_name 時可使用 徹底名稱通配符名稱正則表達式名稱, 它們的匹配順序以下:nginx

  • 徹底匹配
  • 前通配符匹配, 即 *.example.org
  • 後通配符匹配, 即 mail.*
  • 正則表達式匹配

若是沒有匹配到結果, 將會使用 default_server 進行處理, 若是沒有定義, 則第一個定義的爲 default_server. 使用三個簡單的 server 做爲例子, 讓他們監聽 80 端口, server_name 分別設置爲 *.org*.net*.com:正則表達式

server {
    listen      80;
    server_name example.org www.example.org;
    return 401;
}

server {
    listen      80;
    server_name example.net www.example.net;
    return 402;
}

server {
    listen      80;
    server_name example.com www.example.com;
    return 403;
}
複製代碼

在上面的配置中, 默認的服務器爲 第一個, 隨便訪問一個不存在的 server 將會返回 401. 不過可使用 default_server 手動設置一個默認主機, default_server 設置在 listen 字段, 以下:api

server {
    listen      80 default_server;
    server_name example.net www.example.net;
}
複製代碼

以後再匹配時, 未匹配到將會使用這個 server.瀏覽器

禁止訪問

若是想要禁止一個沒有攜帶 Host 字段的請求, 能夠定義以下 server:bash

server {
    listen      80;
    server_name "";
    return      444;
}
複製代碼

server_name 定義爲空字符串, 若是 Host 字段爲空或不存在, 將會匹配到這個 server, 而後返回 404 狀態碼.服務器

Nginx444 狀態比較特殊,若是返回 444 那麼客戶端將不會收到服務端返回的信息,就像是網站沒法鏈接同樣, 瀏覽器直接顯示 502. 可是若是使用反向代理, 仍是顯示正常狀態碼網站

若是想要禁止訪問不存在的主機, 能夠這樣定義:ui

server {
    listen      80 default_server;
    server_name _;
    return      444;
}
複製代碼

_ 在這裏沒有任何特別含義, 由於一個域名中不會出現 _, 因此不會與任何真實的域名相同, 使用其餘非法字符是相同的道理.spa

同時匹配 IPserver_name

如今來看一下對於監聽不一樣 IP 和不一樣 server_name 混合使用時是如何處理的:

server {
    listen      192.168.1.1:80;
    server_name example.org www.example.org;
}

server {
    listen      192.168.1.1:80;
    server_name example.net www.example.net;
}

server {
    listen      192.168.1.2:80;
    server_name example.com www.example.com;
}
複製代碼

在這個配置中, nginx 首先匹配 IP, 匹配到後再匹配它們的 server_name, 若是沒有匹配到 server_name, 則使用到它們默認的 server. 舉個例子, 若是一個域名爲 www.example.com 的請求來自 192.168.1.1:80. 可是監聽 192.168.1.1:80server 只有兩個, 這兩個都不能匹配 www.example.com, 那麼就使用這兩個 server 中的默認主機, 因爲沒有使用 defualt_server 定義監聽, 因此默認爲第一個即 www.example.org 這個 server. 固然你能夠定義 defualt_server:

server {
    listen      192.168.1.1:80;
    server_name example.org www.example.org;
}

server {
    listen      192.168.1.1:80 default_server;
    server_name example.net www.example.net;
}

server {
    listen      192.168.1.2:80 default_server;
    server_name example.com www.example.com;
}
複製代碼

匹配 location

nginx 匹配到一個 server 後, 就會經過 location 繼續處理請求, 下面是一個示例:

server {
    listen      172.17.0.3:80;
    server_name _;

    location / {
        return 401;
    }

    location ~*\.(gif|jpg|png)$ {
        return 402;
    }
    
    location ~*\.(gif|jpg|png)$ {
        return 404;
    }

    location /api {
        return 403;
    }
}
複製代碼

nginx 首先會在全部的 location 中搜索 前綴進行匹配, 匹配到前綴後, 將按順序匹配使用 正則表達式 定義的 location, 匹配到就結束, 若是沒有匹配到, 則使用以前匹配到前綴的那個 location 進行處理, 下面是具體匹配的例子:

  • 一個 /x.gif 請求, 首先匹配到的前綴爲 /, 而後使用剩下的 x.giflocation 的正則去匹配, 先匹配到了 location ~*\.(gif|jpg|png)$, 返回 402.
  • 一個 /x.pdf 請求, 因爲 x.pdf 沒法被匹配到, 因此使用 location / 進行處理.
  • 一個 /api/x.gif, 首先匹配到前綴爲 /api, 而後使用剩下的 x.giflocation 的正則去匹配, 先匹配到了 location ~*\.(gif|jpg|png)$, 返回 402.
  • 一個 /api/x.pdf 請求, 因爲 x.pdf 沒法被匹配到, 因此使用 location /api 進行處理.

參考

How nginx processes a request

server names

相關文章
相關標籤/搜索