概述
經過多年發展,nginx憑借其優異的性能征服了互聯網界,成為了各個互聯網公司架構設計中不可獲取的要素。Nginx是一門大學問,但是對於Web開發者來說,最重要的是需要能捋的清楚Nginx的請求路由配置。
Nginx的路由配置放在配置文件中的Location子節,下面我們來熟練掌握Location的配置。
語法規則
location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
location 為關鍵字 類似java中的case關鍵字,關鍵字后跟隨可選的修飾符,然后是匹配規則(正則匹配和模式匹配),后面的代碼塊為請求處理或轉發的邏輯。
修飾符
一共4種修飾符:
=表示精確匹配。只有請求的url路徑與后面的字符串完全相等時,才會命中。~表示該規則是使用正則定義的,區分大小寫。~*表示該規則是使用正則定義的,不區分大小寫。^~表示前綴匹配,在正則之前。如果該符號后面的字符是最佳匹配,采用該規則,不再進行后續的查找。空修飾符,表示前綴匹配,但是在正則匹配之后。
「=」 修飾符-完全匹配
特點:要求路徑完全匹配
server {
server_name website.com;
location = /abcd {
[…]
}
}
http://website.com/abcd匹配http://website.com/ABCD可能會匹配 ,也可以不匹配,取決於操作系統的文件系統是否大小寫敏感http://website.com/abcd?param1¶m2匹配,忽略 querystringhttp://website.com/abcde**不匹配
「~」修飾符-正則匹配
特點:區分大小寫的正則匹配
server {
server_name website.com;
location ~ ^/abcd$ {
[…]
}
}
注意: ^/abcd$這個正則表達式表示字符串必須以/開始,以$結束,中間必須是abcd
http://website.com/abcd匹配(完全匹配)http://website.com/ABCD不匹配,大小寫敏感http://website.com/abcd?param1¶m2匹配http://website.com/abcd/不匹配,不能匹配正則表達式http://website.com/abcde不匹配,不能匹配正則表達式
「~*」修飾符-正則匹配
特點:不區分大小寫的正則匹配
server {
server_name website.com;
location ~* ^/abcd$ {
[…]
}
}
http://website.com/abcd匹配 (完全匹配)http://website.com/ABCD匹配 (大小寫不敏感)http://website.com/abcd?param1¶m2匹配http://website.com/abcd/不匹配,不能匹配正則表達式http://website.com/abcde不匹配,不能匹配正則表達式
「^~」修飾符-模式匹配
前綴匹配 如果該 location 是最佳的匹配,那么對於匹配這個 location 的字符串, 該修飾符不再進行正則表達式檢測。注意,這不是一個正則表達式匹配,它的目的是優先於正則表達式的匹配
匹配過程
對請求的url序列化。例如,對%xx等字符進行解碼,去除url中多個相連的/,解析url中的.,..等。這一步是匹配的前置工作。
location有兩種表示形式,一種是使用前綴字符,一種是使用正則。如果是正則的話,前面有~或~*修飾符。
具體的匹配過程如下:
首先先檢查使用前綴字符定義的location,選擇最長匹配的項並記錄下來。
如果找到了精確匹配的location,也就是使用了=修飾符的location,結束查找,使用它的配置。
然后按順序查找使用正則定義的location,如果匹配則停止查找,使用它定義的配置。
如果沒有匹配的正則location,則使用前面記錄的最長匹配前綴字符location。
基於以上的匹配過程,我們可以得到以下兩點啟示:
- 使用正則定義的location在配置文件中出現的順序很重要。因為找到第一個匹配的正則后,查找就停止了,后面定義的正則就是再匹配也沒有機會了。
- 使用精確匹配可以提高查找的速度。例如經常請求
/的話,可以使用=來定義location。
匹配規則
原則: 先精確匹配,沒有則查找帶有 ^~的前綴匹配,沒有則進行正則匹配,最后才返回前綴匹配的結果(如果有的話)
- 首先精確匹配 =
- 其次前綴匹配 ^~
- 其次是按文件中順序的正則匹配
- 然后匹配不帶任何修飾的前綴匹配。
- 最后是交給 / 通用匹配
- 當有匹配成功時候,停止匹配,按當前匹配規則處理請求
注意:前綴匹配,如果有包含關系時,按最大匹配原則進行匹配。比如在前綴匹配:location /dir01 與 location /dir01/dir02,如有請求 http://localhost/dir01/dir02/file 將最終匹配到 location /dir01/dir02
匹配邏輯偽代碼:
function match(uri):
rv = NULL
if uri in exact_match:
return exact_match[uri]
if uri in prefix_match:
if prefix_match[uri] is '^~':
return prefix_match[uri]
else:
rv = prefix_match[uri] // 注意這里沒有 return,且這里是最長匹配
if uri in regex_match:
return regex_match[uri] // 按文件中順序,找到即返回
return rv```
URL尾部的/
關於URL尾部的/有三點也需要說明一下。第一點與location配置有關,其他兩點無關。
- location中的字符有沒有
/都沒有影響。也就是說/user/和/user是一樣的。 - 如果URL結構是
https://domain.com/的形式,尾部有沒有/都不會造成重定向。因為瀏覽器在發起請求的時候,默認加上了/。雖然很多瀏覽器在地址欄里也不會顯示/。這一點,可以訪問baidu驗證一下。 - 如果URL的結構是
https://domain.com/some-dir/。尾部如果缺少/將導致重定向。因為根據約定,URL尾部的/表示目錄,沒有/表示文件。所以訪問/some-dir/時,服務器會自動去該目錄下找對應的默認文件。如果訪問/some-dir的話,服務器會先去找some-dir文件,找不到的話會將some-dir當成目錄,重定向到/some-dir/,去該目錄下找默認文件。可以去測試一下你的網站是不是這樣的。
總結
location的配置有兩種形式,前綴字符和正則。查找匹配的時候,先查找前綴字符,選擇最長匹配項,再查找正則。正則的優先級高於前綴字符。
正則的查找是按照在配置文件中的順序進行的。因此正則的順序很重要,建議越精細的放的越靠前。
使用=精准匹配可以加快查找的順序,如果根域名經常被訪問的話建議使用=。
