883 字
4 分钟
深入解析 NGINX `location` 和 `rewrite` 的进阶实战
一、 location 匹配逻辑:谁才是“最终赢家”?
NGINX 的 location 指令看似简单,但当多个规则共存时,匹配顺序至关重要。
1. 匹配优先级图解
NGINX 并不是简单地按照配置文件中从上到下的顺序匹配,而是遵循一套严谨的优先级体系:
| 匹配符号 | 匹配类型 | 优先级 | 备注 |
|---|---|---|---|
= | 精确匹配 | 1 (最高) | 完全匹配 URI,成功后立即停止搜索。 |
^~ | 最佳前缀匹配 | 2 | 只要匹配到前缀,就不再搜索正则表达式。 |
~ | 正则匹配(区分大小写) | 3 | 按配置文件中的先后顺序匹配。 |
~* | 正则匹配(不区分大小写) | 3 | 与 ~ 具有相同优先级。 |
/ | 通用前缀匹配 | 4 (最低) | 如果没有其他匹配,则命中此项。 |
2. 实战示例:配置的最佳实践
# 1. 首页极致优化:精确匹配提升响应速度location = / { proxy_pass http://welcome_page;}
# 2. 静态资源保护:一旦匹配成功,不再检查正则location ^~ /static/ { root /data/web;}
# 3. 附件处理:不区分大小写的正则匹配location ~* \.(zip|rar|pdf)$ { expires 30d;}
# 4. 默认兜底:处理所有动态请求location / { proxy_pass http://app_cluster;}二、 rewrite 深度应用:重写与重定向
rewrite 是流量引导的核心,它的执行过程分为:正则匹配 -> URL 替换 -> 执行 Flag。
1. Flag 标志位的“爱恨情仇”
理解 last 和 break 的区别是区分新手与专家的关键:
last:重写 URL 后,重新启动一套新的location匹配流程。相当于浏览器重新发起了一个内部请求。break:重写 URL 后,直接在当前的location块中处理,不再进行后续匹配。permanent:301 永久重定向(浏览器会缓存),利于 SEO。redirect:302 临时重定向(浏览器不缓存)。
2. 生产环境常用技巧
场景 A:伪静态处理
将动态请求伪装成静态 HTML,提升 SEO 排名:
# 将 /product/123 重写为 /api/item?id=123rewrite ^/product/(\d+)$ /api/item?id=$1 last;场景 B:旧域名跳转新域名
server { listen 80; server_name old-site.com; return 301 https://new-site.com$request_uri; # 现代做法推荐 return,效率高于 rewrite}三、 高阶进阶:if 指令的“避坑”指南
在 NGINX 社区中,有一句著名的座右铭:“If is Evil”。如果在 location 块中不当使用 if,可能会导致不可预知的行为。
1. 推荐用法:简单的变量判断
# 根据移动端展示不同页面if ($http_user_agent ~* (mobile|nokia|iphone|android)) { rewrite ^/(.*)$ /mobile/$1 last;}
# 强制防止跨站请求if ($http_referer !~* "example.com") { return 403;}2. 为什么说 If 危险?
因为 if 指令在内部执行时,有时会跳过某些 location 块的上下文,导致 alias 或 proxy_pass 失效。建议尽可能使用 map 指令或 rewrite 标志位替代复杂的 if 判断。
四、 性能优化与故障排查建议
- 正则效率:正则表达式虽然强大,但会消耗更多 CPU。对于能用前缀匹配(
location /path/)解决的场景,不要使用正则。 - 避免死循环:使用
last时,如果规则编写不当导致 URL 反复重写,NGINX 会在循环 10 次后返回 500 错误。 - 调试利器:在开发环境开启 rewrite 日志。
error_log /var/log/nginx/error.log notice;rewrite_log on;五、 总结
location 决定了请求“去哪儿”,而 rewrite 决定了请求“长什么样”。通过合理组合这两者,你可以实现极其复杂的灰度发布、动静分离以及流量分发。
深入解析 NGINX `location` 和 `rewrite` 的进阶实战
https://sw.rscclub.website/posts/nginxlocationrewrite/