nginx location配置
編寫本文時,使用的nginx版本為nginx/1.17.9和nginx/1.16.1
路由匹配規則
location路由匹配的大致規則:location [=|^~|~|~*|@] path { ... }
如果大家對這塊內容比較熟悉了,可以直接到優先順序疑惑點這裡看一個比較奇怪的匹配邏輯。
精確匹配(=)
location配置的path和客戶端請求的path完全一致時匹配成功。
匹配成功後,nginx就會停止搜尋其他匹配項。
server {
listen 2020;
location = /test {
return 200 '=';
}
}
- 請求
localhost:2020/test
- 請求
localhost:2020/test?num=1
,匹配成功,響應內容為"=" - 請求
localhost:2020/test/
,匹配失敗,響應狀態碼404 - 請求
localhost:2020/test/1
,匹配失敗,響應狀態碼404
字首匹配(^~)
location配置的path為客戶端請求的path字首時匹配成功。
匹配成功後,nginx還會判斷是否存在後面這種情況{(location修飾符為^~
|| location沒有修飾符) && location配置的path是客戶端請求的字首},如果存在,就使用匹配項最多的作為最後的匹配結果。
server { listen 2020; location ^~ /test { return 200 '^~'; } }
- 請求
localhost:2020/test
,匹配成功,響應內容"^~" - 請求
localhost:2020/test/1
,匹配成功,響應內容"^~" - 請求
localhost:2020/test111
,匹配成功,響應內容"^~" - 請求
localhost:2020/tes
,匹配失敗,響應狀態碼404
server {
listen 2020;
location ^~ /test {
return 200 '/test';
}
location ^~ /test/1 {
return 200 '/test/1';
}
}
- 請求
localhost:2020/test
,匹配成功,響應內容"/test" - 請求
localhost:2020/tes
- 請求
localhost:2020/test/1
,匹配成功,響應內容"/test/1"。這裡兩個location配置都匹配上了,第一個location匹配項為1,第二個location匹配項為2,由於nginx選用匹配項最多的location,所以響應內容"/test/1"。
正則匹配(~ 和 ~*)
修飾符~
,正則匹配區分大小寫。修飾符~*
,正則匹配不區分大小寫。
正則匹配以location在檔案中的定義順序從上到下進行匹配。匹配成功以後,nginx就停止搜尋其他匹配項。
注意:mac os檔案系統大小寫不敏感,因此nginx服務配置的location path不區分大小寫,nginx使用~和~效果是一樣的。linux檔案系統大小寫敏感,因此nginx服務區分大小寫,nginx使用~和~效果與前面介紹的效果一致。
~例子
server {
listen 2020;
location ~ /test_a {
return 200 '~';
}
}
- 請求
localhost:2020/test_a
,匹配成功,響應內容"~" - 請求
localhost:2020/test_A
,匹配成功和失敗都有可能,得看nginx服務所在的系統對於大小寫是否敏感。mac os系統下,匹配成功,響應內容"~";linux系統下,匹配失敗,響應狀態碼404。
~*例子
server {
listen 2020;
location ~* /test_a {
return 200 '~*';
}
}
- 請求
localhost:2020/test_a
,匹配成功,響應內容"~*" - 請求
localhost:2020/test_A
,匹配成功,響應內容"~*"
優先順序
注:優先順序從上到下依次遞減。
- 精確匹配(=)
- 字首匹配(^~)
- 正則匹配(~和~*)
- 萬用字元路徑(沒有任何修飾符,只有一個萬用字元路徑"/")
下面我們使用不同的location配置組合來匹配location:2020/test_a
這個請求。
server {
listen 2020;
location ^~ /test_a {
return 200 '^~';
}
location = /test_a {
return 200 '=';
}
}
- 請求
localhost:2020/test_a
,匹配成功,響應內容"=",精確匹配優先順序比字首匹配優先順序大
server {
listen 2020;
location ~ /test_a {
return 200 '~';
}
location ^~ /test_a {
return 200 '^~';
}
}
- 請求
localhost:2020/test_a
,匹配成功,響應內容"^~",字首匹配優先順序比正則匹配優先順序大
server {
listen 2020;
location / {
return 200 '/';
}
location ~ /test_a {
return 200 '~';
}
}
- 請求
localhost:2020/test_a
,匹配成功,響應內容"~",正則匹配優先順序比萬用字元優先順序大
優先順序疑惑點
server {
listen 2020;
location ^~ /test {
return 200 '~';
}
location /test/a {
return 200 'null';
}
}
- 請求
localhost:2020/test/a
,匹配成功,響應內容"null",可以知道第二個location配置優先順序比字首優先順序大,這個在前面字首匹配有介紹。
我們將配置改成下面這個內容:
server {
listen 2020;
location /test {
return 200 'null';
}
location ^~ /test {
return 200 '~';
}
}
然後執行nginx -t
來檢測配置檔案是否正確,得到的結果是:nginx: [emerg] duplicate location "/test" in ...
,這裡的意思是路徑為/test
的location重複了。看到這裡,原本以為"^~"是nginx定義location時預設的修飾符,但是,實際可能並不是,我們看下面的例子。
server {
listen 2020;
location ~ /test {
return 200 '~';
}
location /test/a {
return 200 'null';
}
location ^~ /test {
return 200 '~';
}
}
- 請求
localhost:2020/test/a
,匹配成功,響應內容"~"(what?為什麼返回的不是"null"),這裡三個都匹配上了,但是nginx選用的是正則匹配結果,這個我不知道是什麼原因,如果有大佬知道原因,還請大佬幫忙解惑。
location常用的引數
root & alias
兩個引數都是用來指定檔案路徑。
注:之前很多文章都表示alias配置的路徑最後必須加上"/",這個到現在已經不適用了。我測試的時候,alias配置的路徑最後不新增"/",一樣可以正常使用。
最終指向的檔案路徑區別
- root指向的檔案實際路徑:root+location
- alias指向的檔案實際路徑:alias
server {
listen 2020;
location /test {
root /data;
}
}
最終指向的檔案路徑為/data/test
。
server {
listen 2020;
location /test {
alias /data;
}
}
最終指向的檔案路徑為/data
;
使用上面的配置,我們發起請求localhost:2020/test/1.png
。
- root配置,該請求查詢的檔案路徑為
/data/test/1.png
- alias配置,該請求查詢的檔案路徑為
/data/1.png
定義位置區別
- root可以在http、server、location、if中定義內容
- alias只能在location中定義
root在http、server定義以後,location會預設繼承上層定義的內容,可以在location中使用root對上層root定義進行重寫,或者使用alias讓上層root在該lcation中失效。
正則匹配時定義區別
- root:按照前面說的方式使用
- alias:需要將正則匹配的內容新增到alias定義的路徑後面,具體的例子如下
server {
listen 2020;
location ~ /test {
alias /data;
}
}
請求localhost:2020/test/1.png
,匹配成功,但是沒有找到檔案內容,響應404
server {
listen 2020;
location ~ /test(.*)$ {
alias /data$1;
}
}
請求localhost:2020/test/1.png
,匹配成功,能夠正常返回檔案
proxy_pass
該引數用作反向代理,可以用來做負載均衡、前端解決跨域等功能。使用結構proxy_pass url
。
關於proxy_pass實現負載均衡,可以在nginx負載均衡中看到相關內容。
proxy_pass轉發請求,配置的url最後是否有"/",會呈現不同的效果。
server {
listen 2020;
location /api/ {
proxy_pass http://localhost:7001;
}
}
請求localhost:2020/api/component/list
,nginx會將該請求代理轉發到http://locahost:7001/api/component/list
。
應用場景:前端請求存在跨域,後端介面格式是api/業務路由
,前端請求的介面也是api/業務路由
。
server {
listen 2020;
location /api/ {
proxy_pass http://localhost:7001/;
}
}
請求localhost:2020/api/component/list
,nginx會將該請求代理轉發到http://locahost:7001/component/list
。
應用場景:後端介面格式是業務路由
,前端請求的介面是api/業務路由
,前端請求的介面前面加一個"api"是為了標識某個後端服務,後端介面中並沒用這個標識。
server {
listen 2020;
location /api/ {
proxy_pass http://localhost:7001/online;
}
}
請求localhost:2020/api/component/list
,nginx會將該請求代理轉發到http://locahost:7001/onlinecomponent/list
。
應用場景:沒遇到這樣的場景,一般都會用都會用"/"隔開路徑。
server {
listen 2020;
location /api/ {
proxy_pass http://localhost:7001/online/;
}
}
請求localhost:2020/api/component/list
,nginx會將該請求代理轉發到http://locahost:7001/online/component/list
。
rewrite
rewrite引數用來將客戶端請求重定向到一個新的地址。使用格式rewrite regex replacement [flag];
- regex(必填):正則匹配,只有正則匹配成功後,才能進行地址修改等後續步驟
- replacement(必填):新的url(以
http://
https://
$schema
等開頭)或者uri,正則匹配成功後會用這個值替換原來的請求地址。當replacement值是url時,客戶端請求發生重定向,因此會有兩次請求,第一次請求是客戶端原請求,響應的狀態碼為302,第二次請求的地址就是replacement值,本次rewrite邏輯執行完成以後,後續的rewrite不再匹配;當replacement值為uri時,客戶端請求可能發生重定向,是否發生重定向與flag引數有關 - flag(可選)
- break:本條rewrite邏輯執行完成以後,後續的rewrite不再匹配
- last:本條rewrite邏輯執行完成以後,後續的rewrite不再匹配,重新開始location路由匹配
- permanent:永久重定向,301
- redirect:臨時重定向,302
下面展示幾個例子:
server {
listen 2020;
location / {
rewrite /(.*) https://www.$1.com;
}
}
請求localhost:2020/baidu
,請求被重定向到https://www.baidu.com
。
server {
listen 2020;
location / {
rewrite (.*) https://www.baidu.com;
rewrite (.*) https://www.github.com;
}
}
請求localhost:2020
,請求被重定向到https://www.baidu.com
,檢視network,裡面有一條http://localhost:2020/
請求,響應的狀態碼為302,還以一條https://www.baidu.com/
請求。
server {
listen 2020;
location / {
rewrite (.*) /test redirect; # permanent也是可以的
}
location /test {
return 200 'ok';
}
}
請求localhost:2020
,請求被重定向到http://localhost:2020/test
,network中有兩條請求分別是響應狀態碼302(flag值為permanent時,狀態碼為301)的http://localhost:2020/
請求和響應狀態碼為200的http://localhost:2020/test
請求。
flag值為break或last都會終止後續rewrite匹配(不會終止proxy_pass等邏輯),兩者不同的點是,break不會發起一輪新的location路由匹配,而last會發起一輪新的location匹配。
server {
listen 2020;
location /last {
rewrite /last(.*) /test1;
rewrite /test1(.*) /test2 last;
rewrite /test2(.*) /test3;
}
location /break {
rewrite /break(.*) /test1;
rewrite /test1(.*) /test2 break;
rewrite /test2(.*) /test3;
}
location /test1 {
return 200 'test1';
}
location /test2 {
return 200 'test2';
}
location /test3 {
return 200 'test3';
}
}
- 請求
localhost:2020/last
,響應內容"test2"。這個請求被location /last {...}
匹配成功,因為rewrite /test1(.*) /test2 last
這裡flag為last,所以這條rewrite邏輯執行完以後,就會忽略後續的rewrite,然後重新location路由匹配,重新匹配時請求變成http://localhost:2020/test2
,因此會被location /test2 {}
這條location匹配,所以響應內容為"test2"。 - 請求
localhost:2020/break
,響應狀態碼為404。這個請求被location /break {...}
匹配成功,因為rewrite /test1(.*) /test2 break
這裡flag為break,所以這條rewrite邏輯執行完以後,就會忽略後續的rewrite,執行完當前location後還是沒有找到資原始檔,因此返回狀態碼"404"。
將上面例子中location /break {...}
這部分內容修改一下,修改成如下內容:
location /break {
rewrite /break(.*) /test1;
rewrite /test1(.*) /test2 break;
rewrite /test2(.*) /test3;
proxy_pass http://localhost:2020;
}
- 請求
localhost:2020/break
,響應內容"test2",rewrite語句中flag值為break,不會影響proxy_pass語句,因此localhost:2020/break
實際會代理轉發到localhost:2020/test2
這個地址。
如果rewrite部分內容沒有看懂,可以到搞懂nginx的rewrite模組檢視更詳細的介紹。
index
index用於指定網站的起始頁面,預設值index index.html;
。
index引數只是用來指定檔案的路徑,nginx根據index引數查詢檔案是否存在,如果存在就用檔案路徑拼接成新的url,nginx內部重定向到這個新的url,來獲取到起始頁面資源。下面用具體的例子來進行說明(/data/test目錄下有一個index.html檔案):
server {
listen 2020;
location / {
root /data/test;
index index.html;
}
}
請求localhost:2020
,響應內容為檔案/data/test/index.html
內容。
下面對配置檔案新增一些內容,用來匹配html檔案請求:
server {
listen 2020;
location / {
root /data/test;
index index.html;
}
location ~ \.html$ {
return 200 'html檔案請求攔截';
}
}
請求localhost:2020
,響應內容"html檔案請求攔截"。這個例子很好的說明nginx內部會將初始頁檔案路徑生成一個新的url,nginx內部重定向到這個新的url請求初始頁檔案。
index後面可以跟多個檔案路徑,當前一個檔案不存在時,nginx會自動判斷後面檔案是否存在。下面使用一個例子來展示(/data/test目錄下只有idnex.php檔案):
server {
listen 2020;
location / {
root /data/test;
index index.html index.php;
}
}
請求localhost:2020
,nginx會首先判斷檔案/data/test/index.html
是否存在,如果存在,就使用這個檔案路徑來生成新的檔案url,然後nginx內部重定向到這個檔案資源;如果不存在,就判斷/data/test/index.php
檔案是否存在,如果不存在就返回403,如果存在,就使用這個檔案路徑來生成新的檔案url,然後nginx內部重定向到這個檔案資源