1. 程式人生 > 程式設計 >理解 Nginx 在處理請求時的匹配規則

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

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

匹配 server_name

nginx 中,server_name 決定了當收到一個請求後哪一個 server 會被使用. nginx 會使用請求頭中的 Host 欄位與 server_name 進行匹配. 定義 server_name 時可以使用 完全名稱萬用字元名稱正則表示式名稱,它們的匹配順序如下:

  • 完全匹配
  • 前萬用字元匹配,即 *.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 欄位,如下:

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

之後再匹配時,未匹配到將會使用這個 server.

禁止訪問

如果想要禁止一個沒有攜帶 Host 欄位的請求,可以定義如下 server:

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

server_name 定義為空字串,如果 Host 欄位為空或不存在,將會匹配到這個 server,然後返回 404 狀態碼.

Nginx444 狀態比較特殊,如果返回 444 那麼客戶端將不會收到服務端返回的資訊,就像是網站無法連線一樣,瀏覽器直接顯示 502. 但是如果使用反向代理,還是顯示正常狀態碼

如果想要禁止訪問不存在的主機,可以這樣定義:

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

_ 在這裡沒有任何特別含義,因為一個域名中不會出現 _,所以不會與任何真實的域名相同,使用其他非法字元是相同的道理.

同時匹配 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,返回 402.
  • 一個 /api/x.pdf 請求,所以使用 location /api 進行處理.

參考

How nginx processes a request

server names