一份簡單夠用的 Nginx Location 配置講解

冴羽發表於2022-01-04

前言

Location 是 Nginx 中一個非常核心的配置,這篇重點講解一下 Location 的配置問題以及一些注意事項。

語法

關於 Location,舉個簡單的配置例子:

http { 
  server {
      listen 80;
        server_name www.yayujs.com;
        location / {
          root /home/www/ts/;
          index index.html;
        }
  }
}

大致的意思是,當你訪問 www.yayujs.com80 埠的時候,返回 /home/www/ts/index.html 檔案。

我們看下 Location 的具體語法:

location [ = | ~ | ~* | ^~ ] uri { ... }

重點看方括號中的 [ = | ~ | ~* | ^~ ],其中 | 分隔的內容表示你可能會用到的語法,其中:

  • = 表示精確匹配,比如:
location = /test {
  return 200 "hello";
}

# /test ok
# /test/ not ok
# /test2 not ok
# /test/2 not ok
  • ~ 表示區分大小寫的正則匹配,比如:
location ~ ^/test$ {
  [ configuration ] 
}

# /test ok
# /Test not ok
# /test/ not ok
# /test2 not ok
  • ~* 表示不區分大小寫的正則匹配
location ~* ^/test$ {     
    [ configuration ] 
}

# /test ok
# /Test ok
# /test/ not ok
# /test2 not ok
  • ^~ 表示 uri 以某個字串開頭
location ^~ /images/ {    
    [ configuration ] 
}

# /images/1.gif ok

而當你不使用這些語法的時候,只寫 uri 的時候:

/ 表示通用匹配:

location / {     
    [ configuration ] 
}

# /index.html ok
location /test {
    [ configuration ] 
}

# /test ok
# /test2 ok
# /test/ ok

匹配順序

當存在多個 location 的時候,他們的匹配順序引用 Nginx 官方文件就是:

A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

If the longest matching prefix location has the “^~” modifier then regular expressions are not checked.

Also, using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates. For example, if a “/” request happens frequently, defining “location = /” will speed up the processing of these requests, as search terminates right after the first comparison. Such a location cannot obviously contain nested locations.

翻譯整理後就是:

location 的定義分為兩種:

  • 字首字串(prefix string)
  • 正規表示式(regular expression),具體為前面帶 ~*~ 修飾符的

而匹配 location 的順序為:

  1. 檢查使用字首字串的 locations,在使用字首字串的 locations 中選擇最長匹配的,並將結果進行儲存
  2. 如果符合帶有 = 修飾符的 URI,則立刻停止匹配
  3. 如果符合帶有 ^~ 修飾符的 URI,則也立刻停止匹配。
  4. 然後按照定義檔案的順序,檢查正規表示式,匹配到就停止
  5. 當正規表示式匹配不到的時候,使用之前儲存的字首字串

再總結一下就是:

在順序上,字首字串順序不重要,按照匹配長度來確定,正規表示式則按照定義順序。

在優先順序上,= 修飾符最高,^~ 次之,再者是正則,最後是字首字串匹配。

我們舉幾個簡單的例子複習下:

server {
    location /doc {
        [ configuration A ] 
    }
    location /docu {
        [ configuration B ] 
    }
}

# 請求 /document 使用 configuration B
# 雖然 /doc 也能匹配到,但在順序上,字首字串順序不重要,按照匹配長度來確定
server {
    location ~ ^/doc {
        [ configuration A ] 
    }
    location ~ ^/docu {
        [ configuration B ] 
    }
}

# 請求 /document 使用 configuration A
# 雖然 ~ ^/docu 也能匹配到,但正規表示式則按照定義順序
server {
    location ^~ /doc {
        [ configuration A ] 
    }
    location ~ ^/docu {
        [ configuration B ] 
    }
}

# 請求 /document 使用 configuration A
# 雖然 ~ ^/docu 也能匹配到,但 ^~ 的優先順序更高
server {
    location /document {
        [ configuration A ] 
    }
    location ~ ^/docu {
        [ configuration B ] 
    }
}

# 請求 /document 使用 configuration B
# 雖然 /document 也能匹配到,但正則的優先順序更高

root 與 alias 的區別

當我們這樣設定 root 的時候:

location /i/ {
    root /data/w3;
}

當請求 /i/top.gif/data/w3/i/top.gif 會被返回。

當我們這樣設定 alias 的時候:

location /i/ {
    alias /data/w3/images/;
}

當請求 /i/top.gif/data/w3/images/top.gif 會被返回。

乍一看兩者很像,但細一看,就能看出兩者的區別,root 是直接拼接 root + location 而 alias 是用 alias 替換 location,所以 root 中最後的路徑裡有 /i/,而 alias 中最後的路徑裡沒有 /i/

所以如果你這樣使用 allias 定義一個路徑:

location /images/ {
    alias /data/w3/images/;
}

其實使用 root 會更好:

location /images/ {
    root /data/w3;
}

server 和 location 中的 root

server 和 location 中都可以使用 root,舉個例子:

http { 
  server {
      listen 80;
        server_name www.yayujs.com;
        root /home/www/website/;
        location / {
          root /home/www/ts/;
          index index.html;
        }
  }
}

如果兩者都出現,是怎樣的優先順序呢?

簡單的來說,就是就近原則,如果 location 中能匹配到,就是用 location 中的 root 配置,忽略 server 中的 root,當 location 中匹配不到的時候,則使用 server 中的 root 配置。

系列文章

部落格搭建系列是我至今寫的唯一一個偏實戰的系列教程,講解如何使用 VuePress 搭建部落格,並部署到 GitHub、Gitee、個人伺服器等平臺。

  1. 一篇帶你用 VuePress + GitHub Pages 搭建部落格
  2. 一篇教你程式碼同步 GitHub 和 Gitee
  3. 還不會用 GitHub Actions ?看看這篇
  4. Gitee 如何自動部署 Pages?還是用 GitHub Actions!
  5. 一份前端夠用的 Linux 命令

微信:「mqyqingfeng」,加我進冴羽唯一的讀者群。

如果有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。如果喜歡或者 有所啟發,歡迎 star,對作者也是一種鼓勵。

相關文章