Nginx幾乎是當下絕大多數公司在用的web應用服務,熟悉Nginx的配置,對於我們日常的運維工作是至關重要的,下面就Nginx的location配置進行梳理:
1)location匹配的是nginx的哪個變數?
$request_uri
2)location的匹配種類有哪些?
格式:location [ 空格 | = | ~ | ~* | !~ | !~* | @ ] /uri/ {} 解釋: = 表示精確匹配,如果找到,立即停止搜尋並立即處理此請求。 ~ 表示執行一個正則匹配,區分大小寫匹配 ~* 表示執行一個正則匹配,不區分大小寫匹配 !~ 區分大小寫不匹配 !~* 不區分大小寫不匹配 ^~ 即表示只匹配普通字元(空格)。使用字首匹配,^表示“非”,即不查詢正規表示式。如果匹配成功,則不再匹配其他location。 @ 指定一個命名的location,一般只用於內部重定向請求。例如 error_page, try_files / 表示通用匹配,任何請求都會匹配到 ------------------------------------------------------------------------ 對應示例說明: 1)= server { server_name wangshibo.com; location = /abcd { […] } } 匹配情況: http://wangshibo.com/abcd # 正好完全匹配 http://wangshibo.com/ABCD # 如果執行 Nginx server 的系統本身對大小寫不敏感,比如 Windows ,那麼也匹配 http://wangshibo.com/abcd?param1?m2 # 忽略查詢串引數(query string arguments),這裡就是 /abcd 後面的 ?param1?m2 http://wangshibo.com/abcd/ # 不匹配,因為末尾存在反斜槓(trailing slash),Nginx 不認為這種情況是完全匹配 http://wangshibo.com/abcde # 不匹配,因為不是完全匹配 2)(None) 可以不寫 location modifier ,Nginx 仍然能去匹配 pattern 。這種情況下,匹配那些以指定的 patern 開頭的 URI,注意這裡的 URI 只能是普通字串,不能使用正規表示式。 server { server_name website.com; location /abcd { […] } } 匹配情況: http://wangshibo.com/abcd # 正好完全匹配 http://wangshibo.com/ABCD # 如果執行 Nginx server 的系統本身對大小寫不敏感,比如 Windows ,那麼也匹配 http://wangshibo.com/abcd?param1?m2 # 忽略查詢串引數(query string arguments),這裡就是 /abcd 後面的 ?param1?m2 http://wangshibo.com/abcd/ # 末尾存在反斜槓(trailing slash)也屬於匹配範圍內 http://wangshibo.com/abcde # 仍然匹配,因為 URI 是以 pattern 開頭的 3)~ 這個 location modifier 對大小寫敏感,且 pattern 須是正規表示式 server { server_name wangshibo.com; location ~ ^/abcd$ { […] } } 匹配情況: http://wangshibo.com/abcd # 完全匹配 http://wangshibo.com/ABCD # 不匹配,~ 對大小寫是敏感的 http://wangshibo.com/abcd?param1?m2 # 忽略查詢串引數(query string arguments),這裡就是 /abcd 後面的 ?param1?m2 http://wangshibo.com/abcd/ # 不匹配,因為末尾存在反斜槓(trailing slash),並不匹配正規表示式 ^/abcd$ http://wangshibo.com/abcde # 不匹配正規表示式 ^/abcd$ 注意:對於一些對大小寫不敏感的系統,比如 Windows ,~ 和 ~* 都是不起作用的,這主要是作業系統的原因。 4)~* 與 ~ 類似,但這個 location modifier 不區分大小寫,pattern 須是正規表示式 server { server_name website.com; location ~* ^/abcd$ { […] } } 匹配情況: http://wangshibo.com/abcd # 完全匹配 http://wangshibo.com/ABCD # 匹配,這就是它不區分大小寫的特性 http://wangshibo.com/abcd?param1?m2 # 忽略查詢串引數(query string arguments),這裡就是 /abcd 後面的 ?param1?m2 http://wangshibo.com/abcd/ # 不匹配,因為末尾存在反斜槓(trailing slash),並不匹配正規表示式 ^/abcd$ http://wangshibo.com/abcde # 不匹配正規表示式 ^/abcd$ 5)^~ 匹配情況類似 2. (None) 的情況,以指定匹配模式開頭的 URI 被匹配,不同的是,一旦匹配成功,那麼 Nginx 就停止去尋找其他的 Location 塊進行匹配了(與 Location 匹配順序有關) 6. @ 用於定義一個 Location塊,且該塊不能被外部Client 所訪問,只能被Nginx內部配置指令所訪問,比如try_files 或 error_page location @resize { rewrite ^/(.*)/cache/(.*)?(.*)$ /resize.php?dir=$1&path=$2$3; rewrite ^/(.*)/orgi/cert/(.*)?(.*)$ /pass/resize?dir=$1&type=cert&path=$2$3&is_orgi=true; rewrite ^/(.*)/orgi/card/(.*)?(.*)$ /pass/resize?dir=$1&type=card&path=$2$3&is_orgi=true; rewrite ^/(.*)/orgi/(.*)/(.*)?(.*)$ /pass/resize?dir=$1&type=$2&path=$3$4&is_orgi=true; include fastcgi_params; }
如下示例:
#通用匹配 location / { root /var/www/web/; autoindex on; autoindex_exact_size off; autoindex_localtime on; access_log /var/www/log/nginx/access.log; error_log /var/www/log/nginx/error.log; } #正則匹配 #proxy the php scripts to php-fpm location ~ \.php(.*)$ { root /var/www/web/; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; include fastcgi_params; fastcgi_read_timeout 300; } #精確匹配 location = /hello.php { root /var/www/web/; rewrite ^(.*)$ http://www.wangshibo.com redirect; } 產生的效果如下: 訪問根目錄/,匹配到location / 訪問除hello.php之外的其它php程式,匹配到location ~ \.php$,並且用php5-fpm去執行 訪問hello.php,匹配到location = /hello.php,訪問被重定向到http://www.wangshibo.com
3)location搜尋優先順序順序如何?
精確匹配 > 字串匹配( 長 > 短 [ 注: ^~ 匹配則停止匹配 ]) > 正則匹配( 上 > 下 ) 在nginx的location和配置中location的順序沒有太大關係。正location表示式的型別有關。相同型別的表示式,字串長的會優先匹配。 優先順序排列: 1)等號型別(=)的精確匹配優先順序最高,精確匹配只能命中一個。一旦匹配成功,則不再查詢其他匹配項。 2)^~型別表示式,即字串匹配,使用匹配最長的最為匹配結果。一旦匹配成功,則不再查詢其他匹配項。 3)正規表示式型別(~ ~*)的優先順序次之。如果有多個location的正則能匹配的話,則使用正規表示式最長的那個。 4)常規字串匹配型別。按字首匹配。 特別注意: 字串匹配優先搜尋,但是隻是記錄下最長的匹配 (如果 ^~ 是最長的匹配,則會直接命中,停止搜尋正則),然後繼續搜尋正則匹配,如果有正則匹配,則命中正則匹配,如果沒有正則匹配,則命中最長的字串匹配. 例項說明: 1)先來測試下區分大小寫和不區分大小寫的優先順序.如下: location ~ /5b.txt { return 501 } location ~* /5b.txt { return 504 } 測試結果為: http://192.168.1.80/5b.txt ------------501 http://192.168.1.80/5B.txt ------------504 將順序反下,將~*放前面 location ~* /5b.txt { return 501 } location ~ /5b.txt { return 504 } 測試結果為: http://192.168.1.80/5b.txt ------------501 http://192.168.1.80/5B.txt ------------501 結論: 去分和不區分大小寫的正則匹配優先順序相同,以先後順序來決定匹配哪一個. 2)再來比較=與~的優先順序 location = /5b.txt { return 502 } location ~ /5b.txt { return 504 } 測試結果為: http://192.168.1.80/5b.txt -------------502 結論:=的優先順序比~高 3)再來比較下 ^~ 與 ~的優先順序 location ~ /5b.txt { return 502 } location ^~ /5b.txt { return 504 } 測試結果為: http://192.168.1.80/5b.txt --------------504 結論:^~的優先順序比~高 4)再測試 ^~ 與 = 的優先順序 location ^~ /5b.txt { return 502 } location = /5b.txt { return 504 } 測試結果: http://192.168.1.80/5b.txt --------------504 結論:=的優先順序比 ^~高 5)再來測試^~同級之間的優先順序 location ^~ 5b.txt { return 502 } location ^~ /3a/ { return 504 } 測試結果: http://192.168.1.80/5b.txt --------------504 結論 :^~優先匹配的是從根開始的匹配 6)再來看空格(即什麼都不加)與~的優先順序比較 location /5b.txt { return 502 } location ~ /5b.txt { return 504 } 測試結果為: http://192.168.1.80/5b.txt --------------504 結論:空格的優先順序比~低 優先順序排序為: 空格(即不加) ~與*~正則匹配的優先順序按先後次序來決定的 ^~同級之間的匹配是按照根目錄順序來的 ------------------------------------------------------------------------------------------ 再來看看下面的例子: 1)精確匹配,即“=” location = /images/test.png { echo 'config1'; } location /images/test.png { echo 'config2'; } location \/images\/test\.png$ { echo 'config3'; } 如果此時請求 http://127.0.0.1/images/test.png 輸出的內容是config1, 毋容置疑,精確匹配優先順序最高! 2)精確匹配的特殊情況 location = / { index index.html; } location / { echo 'config2'; } 此時輸入http://127.0.0.1 輸出的內容是config2, 怎麼精確匹配的優先順序不靈了呢? 是這樣的,精確匹配還是起作用了,請求目錄(非具體檔案),nginx會將請求內部定向到index檔案, 既此時真正的請求是http://127.0.0.1/index.html, 這是config2則被命中! 所以精確匹配不要用來匹配/ 3)字串搜尋與正則搜尋 location /images/test.png { echo 'config1'; } location ^~ /images/ { echo 'config2'; } location ~ \/images\/test\.png$ { echo 'config3'; } location ~ \/images\/ { echo 'config4'; } 如果此時請求http://127.0.0.1/images/test.png 輸出的內容是config3,正則命中。 (雖然config1為最長匹配的字串,此時只做記錄,後面還要搜尋正則匹配,則config3正則匹配命中), 仔細觀察可以發現config4也被匹配成功了,但是正則的匹配順序是按照location的定義順序匹配的,所以config3命中. 4)字串匹配優先順序的提升( ^~ ) location /images/ { echo 'config1'; } location ^~ /images/test.png { echo 'config2'; } location ~ /images/test\.png$ { echo 'config3'; } location ~ \/images\/ { echo 'config4'; } 如果此時請求 http://127.0.0.1/images/test.png 輸出的內容是config2, 首部匹配命中。 (因為字串匹配是優先搜尋的,此時發現config2 為最長的字串匹配且為^~匹配方式,所以停止搜尋正則,直接命中!) 所以這裡的 ^~ 符號比較特殊,就是為了提高字串匹配的優先順序,優先於正則匹配. ------------------------------------------------------------------ / 通用匹配,任何請求都會匹配到。 多個location配置的情況下,需要遵循: 首先匹配= 其次匹配^~ 再其次按照配置檔案的順序進行正則匹配、 最後是交給/進行通用匹配 注意:當有匹配成功時,立刻停止匹配,按照當前匹配規則處理請求 看看下面匹配規則: #規則A location = / { } #規則B location = /login { } #規則C location ^~ /static/ { } #規則D location ~ \.(gif|jpg|png|js|css)$ { } #規則E location ~* \.png$ { } #規則F location !~ \.xhtml$ { } #規則G location !~* \.xhtml$ { } #規則H location / { } 那麼產生的效果如下: 1)訪問根目錄/, 比如http://localhost/ 將匹配規則A 2)訪問 http://localhost/login 將匹配規則B,http://localhost/register 則匹配規則H 3)訪問 http://localhost/static/a.html 將匹配規則C 4)訪問 http://localhost/a.gif, http://localhost/b.jpg 將匹配規則D和規則E,但是規則D順序優先,規則E不起作用,而 http://localhost/static/c.png 則優先匹配到規則C 5)訪問 http://localhost/a.PNG 則匹配規則E,而不會匹配規則D,因為規則E不區分大小寫。 6)訪問 http://localhost/a.xhtml 不會匹配規則F和規則G,http://localhost/a.XHTML不會匹配規則G,因為不區分大小寫。規則F,規則G屬於排除法,符合匹配規則但是不會匹配到,所以想想看實際應用中哪裡會用到。 7)訪問 http://localhost/category/id/1111 則最終匹配到規則H,因為以上規則都不匹配,這個時候應該是nginx轉發請求給後端應用伺服器,比如FastCGI(php),tomcat(jsp),nginx作為方向代理伺服器存在。 注意:在實際使用中,至少清楚下面匹配規則 1)直接匹配網站根,通過域名訪問網站首頁比較頻繁,使用這個會加速處理,官網如是說。 2)這裡是直接轉發給後端應用伺服器了,也可以是一個靜態首頁 第一個必選規則: location = / { proxy_pass http://tomcat:8080/index } 第二個必選規則是處理靜態檔案請求,這是nginx作為http伺服器的強項 有兩種配置模式,目錄匹配或字尾匹配,任選其一或搭配使用 location ^~ /static/ { root /webroot/static/; } location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { root /webroot/res/; } 第三個規則就是通用規則,用來轉發動態請求到後端應用伺服器 非靜態檔案請求就預設是動態請求,自己根據實際把握 畢竟目前的一些框架的流行,帶.php,.jsp字尾的情況很少了 location / { proxy_pass http://tomcat:8080/ }
看看下面幾個設定
# 重寫跳轉 rewrite "^/conference/([^/]+)$" /con_detail.php?con_title=$1 last; rewrite "^/conference/([^/]+)/$" /con_detail.php?con_title=$1 last; #遮蔽爬蟲 if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot") { return 403; } #favicon.ico不用打日誌 location = /favicon.ico { log_not_found off; access_log off; } #不允許訪問隱藏檔案 location ~ /\. { deny all; access_log off; log_not_found off; } #訪問圖片,flash檔案等不用打日誌 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 7d; #檔案返回的過期時間是7天 access_log off; } #訪問js和css檔案不用打日誌 location ~ .*\.(js|css)?$ { expires 1d; #檔案返回的過期時間是1天 access_log off; } #設定php-cgi location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; #攔截不存在的php頁面請求 if (!-f $document_root$fastcgi_script_name) { return 404; } }