理解 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
狀態碼.
Nginx
的444
狀態比較特殊,如果返回444
那麼客戶端將不會收到服務端返回的資訊,就像是網站無法連線一樣,瀏覽器直接顯示502
. 但是如果使用反向代理,還是顯示正常狀態碼
如果想要禁止訪問不存在的主機,可以這樣定義:
server {
listen 80 default_server;
server_name _;
return 444;
}
複製程式碼
_
在這裡沒有任何特別含義,因為一個域名中不會出現 _
,所以不會與任何真實的域名相同,使用其他非法字元是相同的道理.
同時匹配 IP
和 server_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:80
的 server
只有兩個,這兩個都不能匹配 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.gif
跟location
的正則去匹配,先匹配到了location ~*\.(gif|jpg|png)$
,返回402
. - 一個
/x.pdf
請求,由於x.pdf
無法被匹配到,所以使用location /
進行處理. - 一個
/api/x.gif
,首先匹配到字首為/api
,返回402
. - 一個
/api/x.pdf
請求,所以使用location /api
進行處理.