Nginx Location 匹配規則詳解與實例
您可能曾經調整過 Nginx 設定、重新載入後,卻發現您的 location 區塊似乎沒有生效。也許靜態檔案請求被 PHP 處理器攔截了,或者 API 路由被一個 catch-all 規則吞掉了。罪魁禍首通常是 Nginx 的 location 匹配演算法——它並不像表面上看起來那麼簡單。
在本指南中,我們將透過您可以實際測試的範例,詳細解析 Nginx 如何選擇 location 區塊。讀完後,您將確切了解哪個區塊會勝出以及原因。
Nginx Location 匹配的運作方式
當請求進來時,Nginx 會將 URI 與所有已定義的 location 區塊進行比對。匹配過程遵循以下順序:
- 精確匹配(
=)——優先順序最高。若找到,Nginx 會停止並使用它。 - 最長前綴匹配——Nginx 會記住最長匹配的前綴 location。
- 正則表達式匹配(
~或~*)——按出現順序檢查。第一個匹配的正則表達式勝出,並覆蓋前綴匹配(除非使用了^~)。 - 帶有
^~的前綴匹配——如果最長匹配的前綴帶有^~,Nginx 會跳過正則檢查並使用它。 - 如果沒有正則表達式匹配,則使用最長前綴匹配。
這就是核心演算法。讓我們看看實際運作情況。
Location 修飾符:快速參考
| 修飾符 | 語法 | 匹配類型 | 優先順序 |
|---|---|---|---|
= | location = /path | 精確 | 最高 |
^~ | location ^~ /path | 前綴(不使用正則) | 高 |
~ | location ~ \.php$ | 正則(區分大小寫) | 中 |
~* | location ~* \.(jpg|png)$ | 正則(不區分大小寫) | 中 |
| 無 | location /path | 前綴 | 最低 |
實際範例 1:靜態檔案與 PHP
考慮這個常見設定:
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
}
對 /index.php 的請求會匹配正則 \.php$,因此會交給 PHP-FPM 處理。對 /logo.png 的請求不匹配正則,因此會回退到前綴 / 並提供靜態檔案。很簡單,對吧?
但如果您想將 /uploads/photo.php 作為靜態檔案提供(也許它實際上是一張圖片)呢?您可以加入一個精確匹配:
location = /uploads/photo.php {
root /var/www/html;
}
現在這個精確匹配的優先順序高於正則表達式。
實際範例 2:使用前綴和正則的 API 路由
假設您有一個位於 /api/ 下的 API,並且您想將所有請求代理到後端,但健康檢查除外,它應該返回靜態回應。
location = /api/health {
return 200 "OK";
}
location /api/ {
proxy_pass http://backend;
}
location ~ ^/api/v[0-9]+/special {
proxy_pass http://special-backend;
}
讓我們追蹤 /api/health:精確匹配勝出,返回 200。對於 /api/users:沒有精確匹配,也沒有正則匹配(不匹配 special),因此使用最長前綴 /api/。對於 /api/v1/special:正則匹配,因此它覆蓋前綴並轉到 special-backend。
這展示了正則如何覆蓋前綴匹配。如果您希望前綴始終勝出,則應改用 ^~。
實際範例 3:^~ 的威力
想像您有一個 /static/ 目錄,其中的檔案即使以 .php 結尾,也絕不應由 PHP 處理。使用 ^~ 可確保 Nginx 不檢查正則 location。
location ^~ /static/ {
root /var/www/html;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
對 /static/script.php 的請求會匹配前綴 ^~ /static/。由於 ^~,Nginx 會跳過正則檢查並直接提供該檔案。如果沒有 ^~,正則會匹配,PHP-FPM 將執行它——這是一個潛在的安全風險。
常見陷阱及如何避免
- 正則順序很重要: Nginx 會按照正則 location 在設定中出現的順序進行檢查。將更具體的模式放在前面。
- 缺少結尾斜線:
location /api和location /api/是不同的。前者匹配/api和/apix,而後者匹配/api/和/api/users。請精確指定。 - 前綴重疊: 最長前綴勝出,因此對於
/api/v1/users,location /api/v1的優先順序高於location /api。 - 忘記為靜態資源使用
^~: 使用它來防止正則劫持靜態檔案請求。 - 大小寫敏感度:
~區分大小寫,~*則不區分。對於檔案副檔名,請使用~*。
除錯 Location 匹配
如果您不確定正在使用哪個 location,請在 Nginx 中啟用除錯記錄。在您的 server 區塊中加入 error_log /var/log/nginx/error.log debug;,重新載入,然後檢查記錄。您會看到類似 test location: "/api/users" 和 using configuration "/api/" 的訊息。
或者,暫時在每個 location 中使用 return 200 "matched: /api/"; 來查看哪個會回應。
常見問題
Nginx location 修飾符的優先順序為何?
精確匹配(=)最高,然後是帶有 ^~ 的最長前綴,然後是按順序的正則(~ 或 ~*),最後是不帶 ^~ 的最長前綴匹配。
正則 location 可以覆蓋前綴 location 嗎?
可以,除非前綴 location 使用了 ^~。正則 location 會在最長前綴匹配之後檢查,如果正則匹配,它的優先順序高於一般前綴。
如何僅針對特定檔案匹配 location?
使用帶有 = 的精確匹配,例如 location = /favicon.ico。這確保只匹配該確切的 URI。
精通您的 Nginx 設定
了解 location 匹配是建立可靠 Nginx 設定的關鍵。使用 nginx -t 測試您的設定,並在遇到疑問時使用除錯記錄。如果您正在處理 Nginx 記錄並需要分析流量模式,請試試我們的 Nginx Log Analyzer,快速解析並視覺化您的記錄。