Nginx 学习笔记:Location 配置详解,五种修饰符与优先级规则实战

一、Location 是什么?为什么重要?

Location 是 Nginx 中最核心的配置指令之一,它决定了一个请求 URL 应该由谁来处理。

location [修饰符] /path/ {
    # 匹配后的处理逻辑
    proxy_pass http://backend;
    # 或 return、root、try_files 等
}

无论是静态文件服务、反向代理、URL 重写还是访问控制,都离不开 location。理解 location 的匹配规则是掌握 Nginx 的必经之路。

本文目标

  • 搞懂五种 location 修饰符的区别
  • 掌握 location 优先级排序规则
  • 通过 Docker 实战测试验证每一个知识点
  • 了解命名 location、try_files、root/alias 等进阶用法

二、五种 Location 修饰符详解

Nginx 的 location 共有 5 种修饰符(也可以说 4 种 + 无修饰符),每一种都有不同的匹配行为。

1. 精确匹配 =

location = /exact {
    # 只匹配 URI 为 /exact 的请求
}
特点 说明
严格相等 URI 必须完全等于指定的路径
不扩散 /exact 不匹配 /exact.html 或 /exact/
优先级 最高,一旦匹配就立即处理,不再检查其他 location

2. 优先前缀匹配 ^~

location ^~ /api/ {
    # 匹配以 /api/ 开头的所有请求
}
特点 说明
前缀匹配 只要 URI 以指定路径开头就匹配
阻止正则 匹配成功后不再检查正则 location(~ 和 ~*)
优先级 仅次于 = 精确匹配

3. 正则匹配 ~(区分大小写)

location ~ \.html$ {
    # 匹配所有 .html 结尾的 URI,区分大小写
}
特点 说明
正则匹配 URI 必须匹配正则表达式
区分大小写 .HTML 不会被匹配
顺序敏感 多个正则按配置顺序匹配,先命中先处理
优先级 低于 ^~,高于普通前缀

4. 正则匹配 ~*(不区分大小写)

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    # 匹配所有图片文件,不区分大小写
}

与 ~ 的唯一区别:不区分大小写。.JPG、.jpg、.Jpg 都会被匹配。

5. 普通前缀匹配(无修饰符)

location /prefix {
    # 匹配以 /prefix 开头的 URI
}
特点 说明
前缀匹配 只要 URI 以指定路径开头就匹配
正则优先 如果也有正则匹配上了,正则胜出
优先级 仅高于默认 /

6. 默认兜底 /

location / {
    # 匹配所有未匹配的请求
}

这是最后的兜底方案,所有没有被其他 location 匹配的请求都会走到这里。优先级最低。


三、Location 里的常用指令(匹配之后做什么?)

Location 决定了"谁来处理请求",但匹配到之后做什么,由里面的指令决定。这些指令才是 location 的真正内容。

1. return — 直接返回响应

return 是 Nginx 里最简单的指令:直接返回一个响应,不再执行后面的任何指令。

return 状态码 [文本] [URL];

三种用法:

# 1. 只返回状态码
return 403;
return 404;

# 2. 返回状态码 + 文本(浏览器直接显示这段文字)
return 200 "请求成功";
return 403 "你没有权限";

# 3. 返回状态码 + URL(浏览器跳转到新地址)
return 301 /new-page;
return 302 http://example.com;

常见状态码:

状态码 含义 return 配合什么
200 OK 正常返回 文本
204 无内容 什么都不加
301 永久重定向 URL(浏览器会缓存这个跳转)
302 临时重定向 URL(下次还问原地址)
403 Forbidden 禁止访问 文本 或 什么都不加
404 Not Found 找不到 文本 或 什么都不加
500 服务器内部错误 文本 或 什么都不加
502 Bad Gateway 后端挂了 文本 或 什么都不加

关键特性:return 之后的指令全部被忽略。

location /api/ {
    return 403 "拒绝访问";
    proxy_pass http://backend;   # ← 这行永远不会执行
    add_header X-Custom "val";   # ← 这行也永远不会执行
}

这就是为什么本文大量用 return 来测试 location 匹配——它只返回一句话,不干别的事,一眼就能看出来"当前请求命中了哪个 location"。

2. proxy_pass — 反向代理(最常用)

location /api/ {
    proxy_pass http://backend-server:3000;
}

把请求转发给后端服务器,后端处理完再把结果返回给客户端。这是 Nginx 作为反向代理的核心用法。

重点:路径拼接规则

很多人搞不清 proxy_pass 的路径是怎么拼的。规则只有一句话:

proxy_pass 的 URL 有路径(包括 /)→ 替换 location 匹配部分
没有路径 → 原样传完整 URI

情况 1:proxy_pass 没有路径 → 原样转发

location /api1/ {
    proxy_pass http://backend:3000;     # ← 末尾没有 /
}
# 请求 /api1/users
# 后端收到 /api1/users(原样)

情况 2:proxy_pass 有 / → 替换掉 location 路径

location /api2/ {
    proxy_pass http://backend:3000/;    # ← 末尾有 /
}
# 请求 /api2/users
# 后端收到 /users(/api2/ 被替换成 /)

情况 3:proxy_pass 有具体路径 → 替换成指定路径

location /api3/ {
    proxy_pass http://backend:3000/app/;  # ← 有具体路径
}
# 请求 /api3/users
# 后端收到 /app/users(/api3/ 被替换成 /app/)

快速记忆

proxy_pass 后端没有路径 → 传完整 URI
proxy_pass 后端有路径   → 替换掉 location 匹配部分

这和之前讲的 alias 是同一个逻辑:有路径就替换,没路径就原样。

3. root — 指定静态文件目录

location /static/ {
    root /var/www;
}
# 请求 /static/js/app.js → 找 /var/www/static/js/app.js

root 是 root路径 + 请求URI 拼接去找文件。

4. alias — 路径别名

location /static/ {
    alias /var/www/html/;
}
# 请求 /static/js/app.js → 找 /var/www/html/js/app.js

alias 是替换:把 location 的路径替换成 alias 的路径。注意末尾 / 的问题,之前已经讲过。

5. try_files — 依次尝试找文件

location / {
    try_files $uri $uri/ /index.html;
}

按顺序尝试:

  1. $uri — 先找当前 URI 对应的文件
  2. $uri/ — 找不到就试目录下的 index
  3. /index.html — 再找不到就返回 SPA 入口

6. rewrite — URL 重写

location /old-path/ {
    rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
}

把 URL 从一种格式重写为另一种。permanent 返回 301,redirect 返回 302,不加就内部重写。

7. index — 默认首页

location / {
    index index.html index.htm;
}

访问目录时默认显示哪个文件。Nginx 会按顺序找,找到哪个返回哪个。

8. add_header — 自定义响应头

location ~* \.(css|js|jpg)$ {
    add_header Cache-Control "public, max-age=86400";
    add_header X-Custom "hello";
}

给响应加 HTTP 头,常用于缓存控制、CORS 跨域、安全策略。

9. expires — 缓存过期时间

location ~* \.(jpg|png|css|js)$ {
    expires 30d;
}

相当于 add_header Cache-Control 的快捷方式。告诉浏览器这个资源可以缓存 30 天。

10. deny / allow — 访问控制

location /admin/ {
    deny all;
    allow 192.168.1.0/24;
}

按 IP 控制访问权限。顺序重要:先允许后拒绝。

11. if — 条件判断

location / {
    if ($request_method = DELETE) {
        return 405;
    }
}

在 location 里做条件判断,通常配合 $invalid_referer、$request_method 等变量使用。

12. set — 设置变量

location / {
    set $cache_key $uri;
    set $debug "true";
}

自定义变量,用于后面的逻辑判断或日志记录。


小结:一个真实 location 里能放什么?

location ^~ /api/ {
    # 访问控制
    deny all;
    allow 192.168.1.0/24;

    # 设置变量
    set $backend "http://app-server:3000";

    # 转发到后端
    proxy_pass $backend;
    proxy_set_header Host $host;

    # 自定义响应头
    add_header X-Upstream "app-server";

    # 超时控制
    proxy_connect_timeout 5s;
    proxy_read_timeout 10s;
}

一个 location 里可以组合多个指令,它们按顺序执行。但 return 是特例——遇到 return 就直接返回了,后面的指令不执行。


四、Location 优先级规则(核心!)

这是 location 配置中最重要的部分。Nginx 的 location 匹配遵循以下优先级顺序:

精确匹配 (=)          ← 优先级最高
    ↓ 未匹配
优先前缀 (^~)         ← 如果匹配,跳过正则
    ↓ 未匹配
正则匹配 (~ / ~*)     ← 按配置顺序匹配,命中即停
    ↓ 未匹配
普通前缀(无修饰符)   ← 取最长的匹配
    ↓ 未匹配
默认兜底 (/)          ← 优先级最低

匹配流程详解

收到请求 URI
    │
    ├─ 第 1 步:检查所有 = 精确匹配
    │   └─ 匹配 → 直接响应 ✅
    │
    ├─ 第 2 步:检查所有 ^~ 优先前缀
    │   └─ 匹配 → 跳过正则,直接响应 ✅
    │
    ├─ 第 3 步:检查所有 ~ / ~* 正则(按配置顺序)
    │   └─ 匹配 → 直接响应 ✅
    │
    ├─ 第 4 步:检查所有普通前缀,取最长匹配
    │   └─ 未匹配 → 走到 /
    │
    └─ 第 5 步:走到 / 默认兜底

关键规则:

  • 正则之间谁先定义谁处理,同一个请求只会被第一个匹配的正则处理
  • 普通前缀取最长的匹配,但如果有正则也匹配,正则胜出
  • ^~ 一旦匹配,完全跳过正则检查

五、Docker 实战测试验证

理论说再多不如动手测一遍。下面我用 Docker 启动 Nginx,实测验证每一条规则。

启动测试环境

# 启动 nginx 容器
docker run -d --name nginx-location -p 19092:80 nginx:latest

# 复制配置文件
docker cp nginx.conf nginx-location:/etc/nginx/nginx.conf

# 重载配置
docker exec nginx-location nginx -s reload

测试配置

# 五种修饰符
location = /exact {
    return 200 "精确匹配 (=) 命中!";
}

location ^~ /api/ {
    return 200 "优先前缀 (^~) 命中!";
}

location ~ \.html$ {
    return 200 "正则 (~) 命中!";
}

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    return 200 "正则 (~*) 命中!";
}

location /prefix {
    return 200 "前缀匹配命中!";
}

location / {
    return 200 "默认兜底 (/) 命中!";
}

测试结果

测试 1:精确匹配 = /exact

curl http://localhost:19092/exact
精确匹配 (=) 命中!
规则: location = /exact
特点: URI 必须完全等于 /exact
优先级: 最高

结论:= /exact 只匹配 /exact,精确无误。

测试 2:精确匹配不扩散

curl http://localhost:19092/exact.html
正则 (~) 命中!
规则: location ~ \.html

结论:= /exact 不会匹配 /exact.html,精确匹配是严格相等。

测试 3:优先前缀 ^~ /api/

curl http://localhost:19092/api/test
优先前缀 (^~) 命中!
规则: location ^~ /api/
特点: 匹配以 /api/ 开头,不再检查正则

测试 4:^~ 阻止正则检查 ⭐

# /api/test.html 同时匹配 ^~ /api/ 和 ~ .html
curl http://localhost:19092/api/test.html
优先前缀 (^~) 命中!

这是最重要的测试之一:即使 .html 正则也匹配,但 ^~ 命中后不再检查正则。

测试 5:正则区分大小写

curl http://localhost:19092/test.html    # 匹配 ✅
curl http://localhost:19092/test.HTML    # 不匹配 ❌

.HTML 不会被 ~ \.html$ 匹配,会走到默认兜底。

测试 6:正则不区分大小写

curl http://localhost:19092/image.JPG
curl http://localhost:19092/image.jpg

两者都会被 ~* \.(jpg|jpeg|png|gif|webp)$ 匹配。

测试 7:前缀 vs 正则冲突 ⭐

# /prefix 和 .html 都匹配
curl http://localhost:19092/prefix/test.html
正则 (~) 命中!

关键知识点:普通前缀和正则都匹配时,正则胜出。

测试 8:正则顺序

location ~ ^/order1 {
    return 200 "第一个正则在前面";
}

location ~ ^/order1 {
    return 200 "第二个永远不会执行";
}
curl http://localhost:19092/order1
顺序测试: 第一个正则在前面

正则按配置顺序匹配,先定义先处理。后面的同名正则永远没有机会执行。


六、进阶用法

1. 命名 Location @

命名 location 不能从外部直接访问,只能通过内部跳转(try_files、error_page 等)调用。

location /test-fallback {
    try_files /nonexistent @error_page;
}

location @error_page {
    return 200 "这是备用处理逻辑";
}
curl http://localhost:19092/test-fallback
命名 location @error_page 命中!

用途:统一的错误处理、备用逻辑、请求收尾。

2. try_files 链式查找

location /tryfiles {
    try_files /test.html /backup.html @final_fallback;
}

按顺序尝试:

  1. 先找 /test.html → 找到就返回
  2. 找不到找 /backup.html → 找到就返回
  3. 都找不到 → 跳到 @final_fallback

非常适用于 SPA(单页应用)的优雅降级和静态文件 fallback。

3. root vs alias 的区别

这是 location 配置中非常容易混淆的两个指令。

指令 路径拼接方式 示例
root root + URI root /var/www; → 请求 /images/1.jpg → /var/www/images/1.jpg
alias alias + (URI - location路径) alias /var/www/; → 请求 /images/1.jpg → /var/www/1.jpg

root 示例:

location /root-test/ {
    root /usr/share/nginx/html;
}
# 请求 /root-test/index.html → /usr/share/nginx/html/root-test/index.html

alias 示例:

location /alias-test/ {
    alias /usr/share/nginx/html/;
}
# 请求 /alias-test/index.html → /usr/share/nginx/html/index.html

⚠️ 重要:alias 末尾的 / 决定了能不能找到文件

alias 的路径末尾必须带 /,否则路径拼接会出错。实测对比:

# ❌ 错误:alias 末尾没有 /
location /alias-test/ {
    alias /usr/share/nginx/html;
}
# 请求 /alias-test/index.html
# → alias 把 /alias-test/ 替换成 /usr/share/nginx/html
# → 结果:/usr/share/nginx/htmlindex.html(斜杠没了!)
# → 404 Not Found ❌


# ✅ 正确:alias 末尾有 /
location /alias-test/ {
    alias /usr/share/nginx/html/;
}
# 请求 /alias-test/index.html
# → alias 把 /alias-test/ 替换成 /usr/share/nginx/html/
# → 结果:/usr/share/nginx/html/index.html
# → 200 OK ✅

为什么 root 没这个问题?

location /test/ {
    root /usr/share/nginx/html;
}

root 的拼接方式是 root路径 + 完整URI:

  • /usr/share/nginx/html + /test/index.html
  • 两个路径之间自然有 / 分隔,所以 root 不需要纠结末尾斜杠
配置 请求 结果 原因
alias /path/; 带 / /test/ 200 ✅ 拼接正确
alias /path; 无 / /test/index.html 404 ❌ /usr/share/nginx/htmlindex.html 少了个斜杠
root /path; 无 / /test/index.html 200 ✅ root 拼接方式自带斜杠

简单记法:alias 是做替换(把 location 路径替换成 alias 路径),替换后斜杠要自己保证;root 是做拼接(root + URI),斜杠天然有。

其他注意:alias 不支持 @ 命名 location,用在正则 location 时行为也不同,建议能用 root 的地方优先用 root。

4. 防盗链实战组合

结合 valid_referers 在 location 中做防盗链:

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    valid_referers none blocked localhost;
    if ($invalid_referer) {
        return 403;
    }
    root /usr/share/nginx/html;
}

测试效果:

# 带本地 Referer → 允许 ✅
curl -e "http://localhost/page.html" http://localhost:19092/image.JPG

# 无 Referer → 允许 ✅(因为有 none)
curl http://localhost:19092/image.JPG

# 盗链 Referer → 拒绝 ❌
curl -e "http://evil.com" http://localhost:19092/image.JPG
# 输出: 盗链检测到!请求被拒绝

七、常见场景与最佳实践

场景 1:静态文件服务

# 精确匹配根路径
location = / {
    index index.html;
}

# 静态资源用正则匹配,缓存策略
location ~* \.(css|js|jpg|png|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

# API 反向代理用 ^~ 避免正则干扰
location ^~ /api/ {
    proxy_pass http://backend;
}

场景 2:SPA 单页应用

location / {
    try_files $uri $uri/ /index.html;
}

所有找不到文件的请求都 fallback 到 index.html,由前端路由处理。

场景 3:动静分离

# 静态资源直接由 Nginx 处理
location ~* \.(jpg|png|css|js)$ {
    root /var/www/static;
    expires 30d;
}

# 动态请求转发给后端
location / {
    proxy_pass http://backend:3000;
}

最佳实践总结

建议 说明
精确路径用 = 如 = /favicon.ico,避免正则检查开销
API 路径用 ^~ 避免被正则意外拦截
文件类型用正则 `~* .(jpg
正则不要重复 同一个模式不要写两个正则,后面的不会执行
/ 放最后 默认兜底始终放在 server 块的最后
测试后再上线 优先级的坑很容易踩,用 curl 逐条验证

八、总结

Location 优先级速查表

优先级  修饰符       示例                     说明
─────────────────────────────────────────────────────
高   │ =           location = /exact        精确匹配
    │ ^~          location ^~ /api/        优先前缀,阻止正则
    │ ~ / ~*      location ~ \.html$       正则匹配(顺序敏感)
    │ 无修饰符    location /prefix         普通前缀(最长优先)
低   │ /           location /              默认兜底

核心要点

要点 说明
=` 最高 完全相等的 URI 用 =,性能最好
^~ 阻止正则 一旦 ^~ 匹配,所有正则都不再检查
正则顺序敏感 正则之间谁先定义谁处理
前缀比不过正则 普通前缀匹配到的请求,如果也有正则匹配,正则胜出
命名 location @name 只能内部跳转,不能外部访问
推荐组合 ^~ 保护 API + 正则处理静态资源 + / 兜底

Nginx 的 location 配置看似简单,但优先级规则在实践中很容易踩坑。记住一句话:= 最高 → ^~ 跳过正则 → 正则顺序匹配 → 普通前缀 → / 兜底。

动手用 Docker 测一遍,比死记硬背有效一百倍。

posted @ 2026-10-13 20:17  PC2005-cloud  阅读(15)  评论(0)    收藏  举报