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,匹配成功,響應內容"/test"
  • 請求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,匹配成功,響應內容"~*"

優先級

注:優先級從上到下依次遞減。

  1. 精確匹配(=)
  2. 前綴匹配(^~)
  3. 正則匹配(~和~*)
  4. 通配符路徑(沒有任何修飾符,只有一個通配符路徑"/")

下面我們使用不同的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內部重定向到這個文件資源。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM