nginx location 知識知多少
- 2020 年 7 月 1 日
- 筆記
寫在之前 眾所周知 nginx location 路由轉發規則多種多樣,尤其是 [ = | ~ | ~* | ^~ ] 這些前綴是什麼意思、root 與 alias 是否可以區分開,nginx 作為反向代理伺服器時,location 中proxy_pass 中配置的上游服務,伺服器後面是否帶/與不帶/是否有區別,帶URI與不帶URI是否有區別等,本文從實踐的角度進行分析總結。 location 中 URI 前綴實踐 匹配語法 nginx 的 uri 匹配模式很強大、並且使用也非常靈活,下面就是nginx的location 相關的所有語法;
location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... }
是的,語法就這一點,是不是感覺很簡單呢?
location [指令模式] uri { ... }
指令模式說明 指令模式有[ = | ~ | ~* | ^~ ], 根據不同的指令模式可分為: 精確匹配:= uri { … } 前綴匹配:^~ uri { … } 正則匹配:~ uri { … } 和 ~* uri { … } 正常匹配:uri { … } 全匹配:/ { … } 指令模式匹配順序 精確匹配 > 前綴匹配 > 正則匹配 > 正常匹配 > 全匹配 實驗說明 測試時,最好不要使用瀏覽器,因為瀏覽器有快取,如果要使用請先清除快取,或者使用curl或者Postman工具等。 精確匹配
# 第1段 location /k8svip/ { root /data/nginx/html4/; index index.html; } # 第2段 location = /k8svip/ { root /data/nginx/html3/; index index.html; }
瀏覽器訪問://127.0.0.1/k8svip/ 根據上面的匹配順序,這裡應該顯示什麼呢?大家都會認為是第2段程式碼中的 = /jdb/ 你可以實驗下,不是的,是第1段,為什麼? 精確匹配中 ‘/k8svip/’中優先匹配到第2段,再訪問’/k8svip/index.html’,此次內部跳轉uri已經是’/k8svip/index.html’,而非 =的;最終訪問結果是第1段中的index.html。
# 第3段 location /k8svip/ { rewrite ^/k8svip/$ //www.baidu.com/ break; } # 第4段 location = /k8svip/ { rewrite ^/k8svip/$ //www.sina.com.cn/ break; }
瀏覽器訪問://127.0.0.1/k8svip/ 看下效果,是不是匹配到第4段了呢?答案:是的;訪問//127.0.0.1/k8sVIP/ ,//127.0.0.1/k8svip/abc 再看下效果,答案:都無法正常訪問。這裡可結合之前的一篇:看了這篇!再不會 Nginx rewrite 算我輸! 結論:精確匹配區分大小寫,不能使用正則,訪問的URI必須完全與=後面的一致,多一個”/”或者少一個”/”,都是不可以的 前綴匹配
location ^~ /k8svip/ { rewrite ^ //www.163.com break; } location ^~ /k8svip/bcd/ { rewrite ^ //www.qq.com break; } location ^~ /Abc/ { rewrite ^ //www.sina.com.cn break; }
訪問://127.0.0.1/k8svip/ 成功,跳轉到163首頁; 訪問://127.0.0.1/k8svip/abcd/成功,只匹配前綴,跳轉到163首頁; 訪問://127.0.0.1/K8svip/ 不成功,區分大小寫,出錯; 訪問://127.0.0.1/k8sVip/123 不成功,區分大小寫,出錯; 訪問://127.0.0.1/Abc/ 成功,區分大小寫,跳轉到新浪首頁; 訪問://127.0.0.1/Abc/abc 成功,只匹配前綴,跳轉到新浪首頁; 結論:前綴匹配不能使用正則,區分大小寫,只要前綴相同,都可以匹配成功,不管後面有沒有字元,保證前綴相同即可。 正則匹配
location ~ /[a-z]k8svip/ { rewrite ^ //www.sina.com.cn break; } location ~* /[a-z]k8svip/ { rewrite ^ //www.google.com break; }
訪問://127.0.0.1/ak8svip/ 成功,正則匹配,會跳轉到新浪首頁; 訪問://127.0.0.1/ak8svip/bbb 成功,正則+前綴匹配,會跳轉到新浪首頁; 訪問://127.0.0.1/zk8svip/ 成功,會跳轉到新浪首頁; 訪問://127.0.0.1/Ak8svip/aaa 成功,這個會跳轉到google.com首頁; 結論:正則匹配 ~ 區分大小寫,~* 不區分大小寫, 並且與前綴匹配比較類似,只需要匹配模式開頭部分,這兩種同時存在時,優先匹配區分大小寫的。 正常匹配(指令模式為空的匹配規則叫正常匹配)
# 第1段 location /k8svip/ { rewrite ^ //www.google.com break; } # 第2段 location /[0-9]k8svip/ { rewrite ^ //www.qq.com break; }
訪問://127.0.0.1/k8svip/ 成功,跳轉google首頁; 訪問://127.0.0.1/k8svip/2 成功,類似前綴匹配,跳轉google首頁; 訪問://127.0.0.1/k8sVIP/ 不成功,區分大小寫,出錯; 訪問://127.0.0.1/0k8svip/ 不成功,不支援正則; 結論:有些文檔中說正常匹配支援正則,不區分大小寫,個人測試了下,不支援正則,但在uri後面繼續跟字元,區分大小寫(相信實驗結果😀,大家可以測試,如果有問題,可以交流,也有可能是版本的差異)正常匹配與前綴匹配的差別,只在於優先順序。
# 第3段 location ^~ /k8svip/ { rewrite ^/k8svip/$ //www.baidu.com/ break; } # 第4段 location /k8svip/ { rewrite ^/k8svip/$ //www.sina.com.cn/ break; }
總結:第3段前綴匹配與第4段正常匹配不能同時存在,否則會報nginx: [emerg] duplicate location “/k8svip/” in /data/nginx//conf/nginx.conf:47 因為這兩個都是普通字元串; 全匹配
location / { root /data/nginx/html; index index.html index.htm; }
說明:沒有匹配指令,並且匹配的URI僅一個斜杠 /,通常用在一個默認頁面的地方,這個地方沒有什麼好說的。 命名匹配
error_page 404 = @notfound; location @notfound { rewrite ^ //www.google.com break; }
說明:一般用於靜態頁面或者錯誤頁面,並且這個命名匹配中,不允許有alias。 優先順序驗證綜合實驗
# 全匹配,這裡/data/nginx/html/下面有一個k8svip文件夾,裡面有index.html location / { root /data/nginx/html; index index.html; } # 正常匹配 location /k8svip/ { rewrite ^/k8svip/$ //www.sina.com.cn/ break; } # 正則匹配 location ~ /[a-z]8svip/ { rewrite ^/k8svip/$ //www.google.com/ break; } # 前綴匹配 location ^~ /k8svip/ { rewrite ^/k8svip/$ //www.baidu.com/ break; } # 精確匹配 location = /k8svip/ { rewrite ^/k8svip/$ //www.qq.com/ break; }
測試方法:把最先匹配的注釋掉,然後再繼續測試,就證明了上面的優先順序 ,注意前綴匹配與正常匹配在相同URI時,不能同時存在; 說明:為了證明以上的優先順序順序, 我們設置了以上的測試用例,為了更進一步說明問題,我們把優先順序最高的放在配置文件的最下面,這樣避免從上到下優先匹配的問題,通過上面的實驗,可以驗證 精確匹配 > 前綴匹配 > 正則匹配 > 正常匹配 > 全匹配 這個指令優先順序順序。 匹配原則除了這個優先順序外,還有一個就是在相同指令模式匹配中,匹配度最大的URI優先; root 與 alias nginx配置 location規則中的 uri 往往都是匹配一個目錄。
location /k8svip/ { root /data/nginx/html/; index index.html index.htm; }
當我們訪問 //127.0.0.1/k8svip/index.html時,如果/data/nginx/html/ 這個目錄下面沒有 k8svip 文件夾,並且它下面沒有index.html或者index.htm,會報404錯誤?原因是使用 root 指定目錄時,目錄下面需要包括location 後面的URI,否則會報錯,即/data/nginx/html/k8svip/index.html,也可以這樣理解,root指定目錄時,不會將location uri配置的路徑去掉,需要在root目錄下面包括uri路徑;
location /k8svip/ { alias /data/nginx/html/; index index.html index.htm; }
當我們訪問 //127.0.0.1/k8svip/index.html時,這裡使用 alias,只要保證alias指定的目錄中有index.html即可,它會將location uri配置的路徑去掉,實際訪問的就是/data/nginx/html/index.html。 結論:root 指定的目錄中,需要location中的 uri 路徑目錄確實存在,alias 指定的目錄中不需要 location中的uri 路徑目錄存在。 代理伺服器 proxy_pass 中有無 / nginx 作為反向代理伺服器時,會使用到proxy_pass,但是proxy_pass 後面 server 有無 / 是有很大區別的,今天通過實驗做下總結; ![](//user-gold-cdn.xitu.io/2020/6/30/17304250f37b4807?w=673&h=164&f=png&s=24144) 上游真實server 192.168.1.3 配置
location /k8svip/ { root /data/nginx/html/; index index.html index.htm; } location /k8svi { root /data/nginx/html/; index index.html index.htm; } location /k3svip/ { root /data/nginx/html/; index index.html index.htm; }
上游真實server 192.168.1.3 驗證
[root@vm-os-centos7 conf]# curl //192.168.1.3/k8svip/ k8svip [root@vm-os-centos7 conf]# curl -L //192.168.1.3/k8svi k8svi [root@vm-os-centos7 conf]# curl //192.168.1.3/k3svip/ k3svip [root@vm-os-centos7 html]# curl //192.168.1.3/k3svipindex k3svipindex.html [root@vm-os-centos7 html]#
代理伺服器 proxy_pass 中無 “/” 驗證
# 實驗 反向代理中後面沒有"/" location /k8svip/ { proxy_pass //192.168.1.3; } # 實驗結果 [root@vm-os-centos7 ~]# curl //192.168.1.2/k8svip/ k8svip [root@vm-os-centos7 ~]# curl -L //192.168.1.2/k8svip k8svip [root@vm-os-centos7 ~]#
192.168.1.3 access.log 日誌如下: 192.168.1.2 – – [17/Jun/2020:21:04:58 +0800] “GET /k8svip/ HTTP/1.0” 200 7 “-” “curl/7.29.0” 結論:如果proxy_pass 反向代理中,在server後面沒有 “/” 反斜杠的話,訪問的是 //192.168.1.3/k8svip/index.html,它會去上游真實伺服器去匹配代理伺服器上面location URI。 代理伺服器 proxy_pass 中有 “/” 驗證
# 實驗 proxy_pass 後面server中有"/" location /k8svip/ { proxy_pass http://192.168.1.3/; } # 實驗結果 [root@vm-os-centos7 conf]# curl //192.168.1.2/k8svip/ <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> </body> </html> [root@vm-os-centos7 conf]#
192.168.1.3 access.log 日誌如下: 192.168.1.2 – – [17/Jun/2020:21:11:17 +0800] “GET / HTTP/1.0” 200 257 “-” “curl/7.29.0” 結論:如果proxy_pass 反向代理中,在server後面有 “/” 反斜杠的話,訪問的是 //192.168.1.3/index.html,它會忽略掉代理伺服器上面location中的URI,直接訪問代理伺服器上面的”/”。 代理伺服器 proxy_pass 後面增加目錄並且加”/””
# 實驗 proxy_pass 後面有目錄,並且目前後面有"/" location /k8svip/ { proxy_pass //192.168.1.3/k3svip/; } # 實驗結果 [root@vm-os-centos7 conf]# curl //192.168.1.2/k8svip/ k3svip [root@vm-os-centos7 conf]#
192.168.1.3 access.log 日誌如下: 192.168.1.2 – – [17/Jun/2020:21:19:11 +0800] “GET /k3svip/ HTTP/1.0” 200 7 “-” “curl/7.29.0″ 結論:如果proxy_pass反向代理中有目錄,並且有”/”反斜杠的話,訪問的是//192.168.1.3/k3svip/index.html,它會忽略掉代理伺服器上面location中的URI,直接訪問代理伺服器上面的目錄+”/”的形式。 代理伺服器 proxy_pass 後面增加 URI,但不加”/”
# proxy_pass 中有目錄,沒有"/" location /k8svip/ { proxy_pass //192.168.1.3/k3svipindex; } # 實驗結果 [root@vm-os-centos7 conf]# curl //192.168.1.2/k8svip/ k3svipindex.html [root@vm-os-centos7 conf]#
192.168.1.3 access.log 日誌如下: 192.168.1.2 – – [17/Jun/2020:21:36:19 +0800] “GET /k3svipindex HTTP/1.0” 200 17 “-” “curl/7.29.0” 結論:如果proxy_pass 反向代理中,在server後面有URI, 但沒有 “/” 反斜杠的話,訪問的是 //192.168.1.3/k3svipindex,它會去上游真實伺服器去匹配代理伺服器上面的URI。 總結 本文通過實驗總結了 location的匹配規則、root與alias的區別、以及nginx作為反向代理伺服器時,proxy_pass 中真實server 是否有”/”反斜杠的區別等。
文章原文地址://www.113p.cn/279.html(113資訊網)