Nginx 的 location 指令如何匹配?优先级是什么?
Nginx 的 location 指令用于匹配请求的 URI,并定义如何处理这些请求。理解 location 的匹配规则和优先级对于正确配置 Nginx 至关重要。
Location 匹配规则:
1. 精确匹配(=)
使用 = 进行精确匹配,如果匹配成功,立即停止搜索并使用该 location。
nginxlocation = /exact { # 精确匹配 /exact }
2. 前缀匹配(无修饰符)
不使用任何修饰符,按前缀匹配,匹配成功后继续搜索更精确的匹配。
nginxlocation /prefix { # 匹配以 /prefix 开头的 URI }
3. 正则匹配(~ 和 ~*)
~:区分大小写的正则匹配~*:不区分大小写的正则匹配
nginxlocation ~ \.php$ { # 匹配以 .php 结尾的 URI(区分大小写) } location ~* \.(jpg|jpeg|png|gif)$ { # 匹配图片文件(不区分大小写) }
4. 前缀匹配(^~)
使用 ^~ 进行前缀匹配,如果匹配成功,立即停止搜索,不再检查正则表达式。
nginxlocation ^~ /static/ { # 匹配以 /static/ 开头的 URI,不再检查正则 }
匹配优先级(从高到低):
- 精确匹配(=):优先级最高
- 前缀匹配(^~):如果匹配成功,停止搜索
- 正则匹配(~ 和 ~*):按配置顺序依次检查
- 前缀匹配(无修饰符):优先级最低
匹配示例:
nginxserver { listen 80; server_name example.com; # 1. 精确匹配 location = / { return 200 "Exact match /"; } # 2. ^~ 前缀匹配 location ^~ /images/ { return 200 "Prefix match ^~ /images/"; } # 3. 正则匹配(区分大小写) location ~ \.php$ { return 200 "Regex match .php"; } # 4. 正则匹配(不区分大小写) location ~* \.(jpg|jpeg|png|gif)$ { return 200 "Regex match images"; } # 5. 普通前缀匹配 location / { return 200 "Prefix match /"; } }
实际匹配结果:
- 请求
/→ 精确匹配location = / - 请求
/images/logo.jpg→location ^~ /images/(停止搜索,不匹配正则) - 请求
/test.php→location ~ \.php$ - 请求
/photo.JPG→location ~* \.(jpg|jpeg|png|gif)$(不区分大小写) - 请求
/other→location /
嵌套 Location:
nginxlocation /api/ { # 外层 location proxy_pass http://backend; location /api/v1/ { # 内层 location,继承外层配置 proxy_pass http://backend_v1; } }
使用建议:
- 将精确匹配放在最前面
- 将正则匹配放在中间
- 将普通前缀匹配放在最后
- 使用
^~避免不必要的正则匹配 - 合理使用正则匹配,避免过度使用影响性能
性能考虑:
- 精确匹配和
^~匹配性能最好 - 正则匹配需要编译和执行,性能相对较低
- 避免使用复杂的正则表达式
- 正则匹配按配置顺序执行,将常用匹配放在前面
实际应用场景:
nginx# 静态文件缓存 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg)$ { expires 1y; add_header Cache-Control "public, immutable"; } # PHP 文件处理 location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; } # API 请求代理 location /api/ { proxy_pass http://api_backend; } # 管理后台 location ^~ /admin/ { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://admin_backend; }