Nginx server 和 location 優先順序
Nginx是一個輕量形的 WEB 伺服器,功能很強大。
其中 server 和 location 可以有很多種的設定方式,也因此需要有個機制去選擇出到底該用哪一個。
這篇文章會說明 Nginx 選擇 server 和 location 的方法。
server的選擇相對比較簡單,在開始之前,要先了解Nginx怎麼編譯 Server 裡面的 listen 。
預設的 listen 通常是 :
listen 80 default_server;
但是一個完整的描述方法因該是:
listen IP:PORT;
而缺少的部分(不管是缺少IP還是Port號)Nginx會自動使用預設值補齊。
補齊的方式如下
缺少IP
如 listen 80;,Nginx會自動補0.0.0.0,變成 :
listen 0.0.0.0:80;
缺少Port
如 listen 10.1.1.1;,Nginx會自動補80 Port號,變成 :
listen 10.1.1.1:80;
兩個都缺
也就是沒有使用 listen ,nginx會自動補上 listen 0.0.0.0:80;
知道自動補齊的方法後,就可以開始討論選擇server的順序。
選擇順序為
listen 有指定IP (如 10.1.1.1)
listen 無指定或使用0.0.0.0
當第一個IP:Port匹配檢查完後,發現有多個符合的結果,才會繼續比對。
選擇順序為
1. 完整比對到server_name,如 server_name www.example.com;
2. server_name前面有 * 符號,如 server_name *.example.com;
3. server_name後面有 * 符號,如 server_name www.*;
4. server_name是正規表示法,如 server_name ~www.example[1-3].com;
5. 全部的server_name都不匹配,此時Nginx會使用 listen 後面有 default_server字樣的
如 :
listen 80 default_server;
server_name _;
這邊先說明單純的 location 選擇機制。
之所以使用機制這個說法,是因為在選擇的過程中並不像 server 這樣順序往下看。
下面的步驟中,出現 則使用 這個文字,代表Nginx不會再去看其它的 location ,而是選擇這個 location。
首先要介紹這邊會用到的 location種類 :
none - location後面沒有任何特殊符號,如 location /var/www {...}
= - location後面帶 = 符號,如 location = /var/www {...}
^~ - location後面帶 ^~ 符號,如 location ^~ /var/www {...}
~或~* - location後面帶 ~或~* 符號,如 location ~ /var/www {...}
稍為說明一下這些的功能:
none - 最普通的寫法。
= - 精確匹配,Client送進來的 URI必須完全一樣。
^~ - 排除正規表示法的匹配,功能等同 none ,可是使用的優先權高於正規表示法
~ - 正規表示法,區分大小寫
~* - 正規表示法,不區分大小寫
(URI,以 "http://abc.com/image/logo.png" 這個為例,http:// 是 protocol,abc.com 是host_name或server name,/image/logo.png 這個就是 URI)
(在nginx內,$host_name沒有帶Port號,$server_name有帶Port號)
2. location 後面使用 = 符號,並且精確匹配到,則使用。如 location = /var/www {
3. 匹配none locaiotn ,並且匹配到最長符合的項目。
3.1這個 "最長符合的項目" 如果是 ^~,則使用。如 location ^~ /var/www {
3.2 把這個 "最長符合的項目" 儲存起來。
如 : location /var 和 location /var/www,location /var/www 會被儲存。
4. 尋找全部的正規表示法,第一個被匹配到的,則使用。因此正規表示法的上下順序很重要。
5. 全部的正規表示法都找不到,使用 剛剛儲存的"最長符合的項目" 的none location。
如 : location /var/www {
location / {...}
location /image {...}
location = /image/server1/png {...}
location ^~ /image/server1 {...}
location ~* ^/image {...}
location ~* ^/image/server[1-3] {...}
1.
Client 送一個請求為,http://abc.com/image/server1/png/logo.png,這個請求的URI為 :
/image/server1/png/logo.png
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location ^~ /image/server1 {...} ,因為是用 ^~ 符號,因此使用這個locaiotn。
2.
Client 送一個請求為,http://abc.com/image/server2/png/logo.png,這個請求的URI為 :
/image/server2/png/logo.png
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location /image {...} ,因為沒有符號,因此先儲存。
3. 尋找正規表示的location,第一個匹配成功的是,location ~* ^/image {...},因此使用這個locaiotn。
3.
Client 送一個請求為,http://abc.com/www/index.html,這個請求的URI為 :
/www/index.html
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location / {...} ,因為沒有符號,因此先儲存。
3. 尋找正規表示的location,但是找不到匹配的。
4. 使用原本的 "最長符合" 的location,location / {...}。
會發生內部重新導向的狀況主要是有底下幾個語法 :
(執行的優先順序也會照這個順序進行)
會使rewrite造成不同的行為,其中會有以下的行為。
造成內部重新導向 :
不加參數
last
將請求返回給客戶端,讓客戶端再發送一個請求 :
(會造成客戶端的重新導向)
redriect
permanent
不進行內部重新導向
break
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
location / {
rewrite ^/example/(.*)$ /$1 last;
}
location /default {
index index.html;
}
請求會先進到 "location /" 裡面,因為有使用 rewrite 語法,經過rewrite修改後的請求會變成 "/default"。
並且 rewrite 後面帶的參數是 last,因此Nginx會產生內部重新導向,跳到 "location /default",繼續進行請求的處理。
如 : try_file $uri $uri/ /default/error.html;
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
location / {
try_file $uri $uri/ /default/error.html;
}
location /default {
index index.html;
}
請求會先進到 "location /" 裡面,並且依序尋找 :
"/var/www/html/example/default" 這個檔案
"/var/www/html/example/default/" 這個資料夾
當上面兩個都找不到時,重新導向到 /default/error.html
!!注意 : 當try_file和rewrite寫在同一個location時,會優先執行rewrite。
如以下設定,Nginx還是會先進行rewrite處理。
root /var/www/html;
location / {
try_file $uri $uri/ /default/error.html;
rewrite ^/example/(.*)$ /$1 last;
}
location /default {
index index.html;
}
如 "/example/default/" 或 最基本的 "/"。
index 也可以包含URI在裡面,如 index index.html /default/index.html,當找不到index.html,就會被內部重新導向到/default。
舉個例子
有一個請求是 /example/default/
且設定檔如下
root /var/www/html;
index index.html /default/index.htm;
location / {
access_log /var/log/nginx/access.log;
}
location /default {
access_log /var/log/default.log;
}
請求會先進到 "location /" 裡面,並且依序尋找 :
"/var/www/html/example/default/index.html" 這個檔案
"/var/www/html/default/index.htm" 這個檔案
!!注意 : 404 錯誤回傳的網頁大小不能大於512K。
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
index index.html /default/index.htm;
location / {
error_page 404 /fail/page.html;
}
location /fail {
access_log /var/log/404.log;
}
請求會先進到 "location /" 裡面,並且尋找 :
"/var/www/html/example/default" 這個檔案
當找不到時,Nginx會產生404錯誤碼,這時會觸發 error_page 404。
被重新導向到 "/fail/page.html"。
其中 server 和 location 可以有很多種的設定方式,也因此需要有個機制去選擇出到底該用哪一個。
這篇文章會說明 Nginx 選擇 server 和 location 的方法。
Server
當設定檔中有多個 server (...) 區塊,Nginx會怎麼選擇呢?server的選擇相對比較簡單,在開始之前,要先了解Nginx怎麼編譯 Server 裡面的 listen 。
預設的 listen 通常是 :
listen 80 default_server;
但是一個完整的描述方法因該是:
listen IP:PORT;
而缺少的部分(不管是缺少IP還是Port號)Nginx會自動使用預設值補齊。
補齊的方式如下
缺少IP
如 listen 80;,Nginx會自動補0.0.0.0,變成 :
listen 0.0.0.0:80;
缺少Port
如 listen 10.1.1.1;,Nginx會自動補80 Port號,變成 :
listen 10.1.1.1:80;
兩個都缺
也就是沒有使用 listen ,nginx會自動補上 listen 0.0.0.0:80;
知道自動補齊的方法後,就可以開始討論選擇server的順序。
首先
Nginx會先檢查 IP:Port 的匹配。選擇順序為
listen 有指定IP (如 10.1.1.1)
listen 無指定或使用0.0.0.0
第二
比對 server_name當第一個IP:Port匹配檢查完後,發現有多個符合的結果,才會繼續比對。
選擇順序為
1. 完整比對到server_name,如 server_name www.example.com;
2. server_name前面有 * 符號,如 server_name *.example.com;
3. server_name後面有 * 符號,如 server_name www.*;
4. server_name是正規表示法,如 server_name ~www.example[1-3].com;
5. 全部的server_name都不匹配,此時Nginx會使用 listen 後面有 default_server字樣的
如 :
listen 80 default_server;
server_name _;
Location
location的選擇比較複雜,如果再加上內部重新導向的功能,選擇上更加複雜。這邊先說明單純的 location 選擇機制。
之所以使用機制這個說法,是因為在選擇的過程中並不像 server 這樣順序往下看。
下面的步驟中,出現 則使用 這個文字,代表Nginx不會再去看其它的 location ,而是選擇這個 location。
首先要介紹這邊會用到的 location種類 :
none - location後面沒有任何特殊符號,如 location /var/www {...}
= - location後面帶 = 符號,如 location = /var/www {...}
^~ - location後面帶 ^~ 符號,如 location ^~ /var/www {...}
~或~* - location後面帶 ~或~* 符號,如 location ~ /var/www {...}
稍為說明一下這些的功能:
none - 最普通的寫法。
= - 精確匹配,Client送進來的 URI必須完全一樣。
^~ - 排除正規表示法的匹配,功能等同 none ,可是使用的優先權高於正規表示法
~ - 正規表示法,區分大小寫
~* - 正規表示法,不區分大小寫
(URI,以 "http://abc.com/image/logo.png" 這個為例,http:// 是 protocol,abc.com 是host_name或server name,/image/logo.png 這個就是 URI)
(在nginx內,$host_name沒有帶Port號,$server_name有帶Port號)
選擇機制為 :
1. 先搜索一次全部的none location。如 location /var/www {2. location 後面使用 = 符號,並且精確匹配到,則使用。如 location = /var/www {
3. 匹配none locaiotn ,並且匹配到最長符合的項目。
3.1這個 "最長符合的項目" 如果是 ^~,則使用。如 location ^~ /var/www {
3.2 把這個 "最長符合的項目" 儲存起來。
如 : location /var 和 location /var/www,location /var/www 會被儲存。
4. 尋找全部的正規表示法,第一個被匹配到的,則使用。因此正規表示法的上下順序很重要。
5. 全部的正規表示法都找不到,使用 剛剛儲存的"最長符合的項目" 的none location。
如 : location /var/www {
location 範例說明 :
設定檔如下 :location / {...}
location /image {...}
location = /image/server1/png {...}
location ^~ /image/server1 {...}
location ~* ^/image {...}
location ~* ^/image/server[1-3] {...}
1.
Client 送一個請求為,http://abc.com/image/server1/png/logo.png,這個請求的URI為 :
/image/server1/png/logo.png
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location ^~ /image/server1 {...} ,因為是用 ^~ 符號,因此使用這個locaiotn。
2.
Client 送一個請求為,http://abc.com/image/server2/png/logo.png,這個請求的URI為 :
/image/server2/png/logo.png
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location /image {...} ,因為沒有符號,因此先儲存。
3. 尋找正規表示的location,第一個匹配成功的是,location ~* ^/image {...},因此使用這個locaiotn。
3.
Client 送一個請求為,http://abc.com/www/index.html,這個請求的URI為 :
/www/index.html
依照機制 :
1. 找 = 符號的 location,location = /image/server1/png {...},但是這個沒有精確匹配到
2. 找最長符合,找到 location / {...} ,因為沒有符號,因此先儲存。
3. 尋找正規表示的location,但是找不到匹配的。
4. 使用原本的 "最長符合" 的location,location / {...}。
內部重新導向
所謂 "內部重新導向" 就是原本在某一個 location 內處理,因為設定的語法會跑到其它 location 或再一次進到相同的 location 進行處理。會發生內部重新導向的狀況主要是有底下幾個語法 :
(執行的優先順序也會照這個順序進行)
- rewrite
- try_file
- index
- error_page
rewrite
rewrite後面可以再放置參數,如 rewrite ^/example/(.*)$ /$1 last;會使rewrite造成不同的行為,其中會有以下的行為。
造成內部重新導向 :
不加參數
last
將請求返回給客戶端,讓客戶端再發送一個請求 :
(會造成客戶端的重新導向)
redriect
permanent
不進行內部重新導向
break
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
location / {
rewrite ^/example/(.*)$ /$1 last;
}
location /default {
index index.html;
}
請求會先進到 "location /" 裡面,因為有使用 rewrite 語法,經過rewrite修改後的請求會變成 "/default"。
並且 rewrite 後面帶的參數是 last,因此Nginx會產生內部重新導向,跳到 "location /default",繼續進行請求的處理。
try_file
try_file可以讓Nginx進行一系列的檔案或資料夾的查找,並可在最後放置一個URI讓Nginx進行內部重新導向。如 : try_file $uri $uri/ /default/error.html;
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
location / {
try_file $uri $uri/ /default/error.html;
}
location /default {
index index.html;
}
請求會先進到 "location /" 裡面,並且依序尋找 :
"/var/www/html/example/default" 這個檔案
"/var/www/html/example/default/" 這個資料夾
當上面兩個都找不到時,重新導向到 /default/error.html
!!注意 : 當try_file和rewrite寫在同一個location時,會優先執行rewrite。
如以下設定,Nginx還是會先進行rewrite處理。
root /var/www/html;
location / {
try_file $uri $uri/ /default/error.html;
rewrite ^/example/(.*)$ /$1 last;
}
location /default {
index index.html;
}
index
一般 index 是用做當請求的最後一個文字是 "/" 符號時,進行一系列檔案的查找。如 "/example/default/" 或 最基本的 "/"。
index 也可以包含URI在裡面,如 index index.html /default/index.html,當找不到index.html,就會被內部重新導向到/default。
舉個例子
有一個請求是 /example/default/
且設定檔如下
root /var/www/html;
index index.html /default/index.htm;
location / {
access_log /var/log/nginx/access.log;
}
location /default {
access_log /var/log/default.log;
}
請求會先進到 "location /" 裡面,並且依序尋找 :
"/var/www/html/example/default/index.html" 這個檔案
"/var/www/html/default/index.htm" 這個檔案
error_page
這個功能是定義當出現錯誤代碼時,要導到那個頁面。!!注意 : 404 錯誤回傳的網頁大小不能大於512K。
舉個例子
有一個請求是 /example/default
且設定檔如下
root /var/www/html;
index index.html /default/index.htm;
location / {
error_page 404 /fail/page.html;
}
location /fail {
access_log /var/log/404.log;
}
請求會先進到 "location /" 裡面,並且尋找 :
"/var/www/html/example/default" 這個檔案
當找不到時,Nginx會產生404錯誤碼,這時會觸發 error_page 404。
被重新導向到 "/fail/page.html"。
非常的有幫助,感謝!
回覆刪除try_file 要改成 try_files 喔xd ,不然會error
回覆刪除感謝分享, 真的是簡單易懂
回覆刪除