Nginx location 匹配与路径映射详解
location 只负责匹配 URL,真正决定怎么转发/映射的是 proxy_pass、root、alias 等指令。
一、先理解:location 匹配的是什么?
text
location /api/ {
# 这里的 /api/ 匹配的是 URL 中的路径部分
# 例如:http://example.com/api/users → 匹配 /api/users
}
关键点:location 匹配的是 URI 的路径部分(不包括域名、协议、参数)。
二、静态文件服务:root vs alias
1. root(拼接模式)
text
location /images/ {
root /var/www;
}
映射规则:root 路径 + 请求 URI = 实际文件路径
| 请求 URL | 实际查找文件 |
|---|---|
/images/logo.png |
/var/www/images/logo.png |
/images/photo/1.jpg |
/var/www/images/photo/1.jpg |
特点:root 会保留 location 匹配的路径作为子目录。
2. alias(替换模式)
text
location /images/ {
alias /var/www/static/;
}
映射规则:alias 路径 + (请求 URI 去掉 location 匹配部分) = 实际文件路径
| 请求 URL | 实际查找文件 |
|---|---|
/images/logo.png |
/var/www/static/logo.png |
/images/photo/1.jpg |
/var/www/static/photo/1.jpg |
特点:alias 会剥离 location 匹配的路径前缀。
root vs alias 对比示例
text
# 假设请求 /static/css/style.css
# 使用 root
location /static/ {
root /var/www;
}
# 实际查找:/var/www/static/css/style.css ✅
# 使用 alias
location /static/ {
alias /var/www/assets/;
}
# 实际查找:/var/www/assets/css/style.css ✅
# 常见错误:alias 末尾忘记加斜杠
location /static/ {
alias /var/www/assets; # ❌ 错误!
}
# 实际查找:/var/www/assetscss/style.css (拼接错误)
三、反向代理:proxy_pass 的路径映射
核心规则:proxy_pass 是否带斜杠 / 决定路径如何处理
1. proxy_pass 不带斜杠(原样转发)
text
location /api/ {
proxy_pass http://backend; # 注意:没有斜杠
}
规则:保留 location 匹配的部分
| 请求 URL | 转发到后端 |
|---|---|
/api/users |
http://backend/api/users |
/api/order/123 |
http://backend/api/order/123 |
2. proxy_pass 带斜杠(剥离前缀)
text
location /api/ {
proxy_pass http://backend/; # 注意:有斜杠
}
规则:去掉 location 匹配的前缀
| 请求 URL | 转发到后端 |
|---|---|
/api/users |
http://backend/users |
/api/order/123 |
http://backend/order/123 |
3. 更精确的控制(使用变量)
text
location /api/ {
# 完全重写路径
rewrite ^/api/(.*)$ /v2/$1 break;
proxy_pass http://backend;
}
# /api/users → /v2/users
# 或使用 $uri 变量
location /api/ {
proxy_pass http://backend$request_uri;
}
# 原样转发(包含参数)
四、完整示例:常见场景
场景1:静态文件服务
text
server {
listen 80;
server_name example.com;
# 方案1:使用 root(保留路径)
location /static/ {
root /var/www;
# /static/css/style.css → /var/www/static/css/style.css
}
# 方案2:使用 alias(剥离路径)
location /assets/ {
alias /var/www/public/;
# /assets/logo.png → /var/www/public/logo.png
}
# 方案3:精确匹配首页
location = / {
root /var/www/html;
index index.html;
}
}
场景2:API 网关(路径重写)
text
upstream backend_api {
server 192.168.1.10:8080;
}
server {
listen 80;
# 需求1:/api/users → 转发到 /users(去掉 /api)
location /api/ {
proxy_pass http://backend_api/; # 注意斜杠
proxy_set_header Host $host;
}
# 需求2:/v1/users → 转发到 /v1/users(保留原样)
location /v1/ {
proxy_pass http://backend_api; # 无斜杠
}
# 需求3:/old/xxx → 转发到 /new/xxx(重写)
location /old/ {
rewrite ^/old/(.*)$ /new/$1 break;
proxy_pass http://backend_api;
}
# 需求4:完全自定义转发路径
location /legacy/ {
proxy_pass http://backend_api/custom/path/;
# /legacy/user → /custom/path/user
}
}
场景3:前后端分离项目
text
server {
listen 80;
server_name myapp.com;
# 前端:根路径返回静态 HTML
location / {
root /var/www/frontend/dist;
try_files $uri $uri/ /index.html; # SPA 路由支持
}
# 后端 API:转发到 Node.js
location /api/ {
proxy_pass http://localhost:3000/; # 去掉 /api 前缀
proxy_set_header X-Real-IP $remote_addr;
}
# 文件上传:特殊处理
location /upload/ {
proxy_pass http://localhost:3000/files/; # 改变路径
client_max_body_size 50M;
}
# 静态资源:直接返回(加缓存)
location ~* \.(js|css|png|jpg)$ {
root /var/www/frontend/dist;
expires 30d;
}
}
五、测试映射规则的方法
1. 使用 echo 模块测试(最直接)
text
location /api/ {
# 回显转发路径
add_header Content-Type text/plain;
return 200 "Will proxy to: http://backend$request_uri\n";
}
2. 查看 Nginx 错误日志
text
location /api/ {
# 开启调试日志
proxy_pass http://backend/;
error_log /var/log/nginx/debug.log debug;
}
3. 使用 curl 测试
bash
# 查看实际转发的请求
curl -v http://localhost/api/users
# 在后端服务器抓包
tcpdump -i lo -A port 8080
六、核心规则速查表
| 配置 | 请求 | 实际转发/查找 | 说明 |
|---|---|---|---|
root /var/www; |
/static/a.css |
/var/www/static/a.css |
root 保留路径 |
alias /var/www/; |
/static/a.css |
/var/www/a.css |
alias 剥离前缀 |
proxy_pass http://backend; |
/api/users |
http://backend/api/users |
保留原路径 |
proxy_pass http://backend/; |
/api/users |
http://backend/users |
剥离 location 前缀 |
proxy_pass http://backend/v2; |
/api/users |
http://backend/v2users |
⚠️ 陷阱(缺斜杠) |
proxy_pass http://backend/v2/; |
/api/users |
http://backend/v2/users |
完全替换路径 |
七、常见陷阱与最佳实践
❌ 错误示例
text
# 陷阱1:alias 缺少末尾斜杠
location /static/ {
alias /var/www/static; # ❌
# /static/a.css → /var/www/statica.css
}
# 陷阱2:proxy_pass 路径混淆
location /api {
proxy_pass http://backend/; # ⚠️ 注意 /api 没有尾斜杠
# /api/users → http://backend//users(双斜杠)
}
# 陷阱3:location 和 proxy_pass 斜杠不匹配
location /api/ {
proxy_pass http://backend; # ⚠️ /api/ 有斜杠,backend 无斜杠
# /api/users → http://backend/api/users ✅ 实际正确,但容易混淆
}
✅ 最佳实践
text
# 1. 统一风格:location 和 proxy_pass 都带斜杠
location /api/ {
proxy_pass http://backend/; # 剥离前缀
}
# 2. 或统一不带(保留原样)
location /api {
proxy_pass http://backend; # 保留前缀
}
# 3. 使用变量明确控制
location /api/ {
set $backend_url "http://backend";
proxy_pass $backend_url$request_uri; # 明确意图
}
# 4. 复杂重写用 rewrite
location /legacy/ {
rewrite ^/legacy/(.*)$ /api/v2/$1 break;
proxy_pass http://backend;
}
八、记忆口诀
root 拼接保留路径,alias 替换要剥去
proxy_pass 带斜杠剥离,不带斜杠原样转
location 尾斜杠要小心,两边对齐不出错
快速判断规则:
- root:请求路径追加到 root 后面
- alias:请求路径去掉 location 后再追加
- proxy_pass 无斜杠:转发原路径
- proxy_pass 有斜杠:转发去掉 location 匹配部分后的路径
评论
欢迎留下反馈,评论发布后会立即显示。