深入理解 Nginx location 匹配规则与代理配置
本文是 Nginx 实操专栏的第三篇,我们将深入探讨 location 匹配规则、优先级以及 proxy_pass 的使用方法,帮助你掌握 Nginx 最核心的功能之一。
引言
在前面两篇文章中,我们分别介绍了 Nginx 的架构原理和配置结构。今天我们将深入探讨 Nginx 最重要的功能之一:location 匹配规则和代理配置。这是构建复杂 Web 应用和 API 网关的基础。
location 匹配规则详解
location 指令用于根据 URI 匹配不同的请求,并执行相应的处理逻辑。理解 location 的匹配规则对正确配置 Nginx 至关重要。
location 匹配语法
location [modifier] uri { ... }其中 modifier 是可选的修饰符,决定了匹配的方式。
匹配修饰符类型
1. 精确匹配 (=)
location = / {
# 只匹配 "/"
# 例如: http://example.com/
}这是优先级最高的匹配方式,一旦匹配成功,不再检查其他 location。
2. 前缀匹配 (无修饰符)
location /documents/ {
# 匹配以 "/documents/" 开头的所有 URI
# 例如: /documents/, /documents/file.html, /documents/subdir/file.pdf
}3. 优先前缀匹配 (^~)
location ^~ /images/ {
# 匹配以 "/images/" 开头的 URI
# 如果匹配成功,则不再进行正则表达式匹配
}4. 正则表达式匹配 (~ 和 ~*)
# 区分大小写的正则匹配
location ~ \.(gif|jpg|png)$ {
# 匹配以 .gif, .jpg, .png 结尾的请求
}
# 不区分大小写的正则匹配
location ~* \.(GIF|JPG|PNG)$ {
# 匹配以 .GIF, .JPG, .PNG 结尾的请求(忽略大小写)
}匹配优先级规则
Nginx 按照以下顺序进行 location 匹配:
- 精确匹配 (=) - 优先级最高
- 优先前缀匹配 (^~) - 匹配成功后停止正则匹配
- 正则表达式匹配 (~ 和 ~*) - 按照配置文件中的顺序进行匹配
- 最长前缀匹配 - 选择匹配长度最长的前缀
实际匹配示例
server {
listen 80;
server_name example.com;
# 精确匹配
location = / {
# 只匹配 http://example.com/
return 200 "Exact match for /\n";
}
# 优先前缀匹配
location ^~ /images/ {
# 匹配 /images/ 开头的所有请求
# 即使有正则匹配 /images/\.png$,也不会被执行
return 200 "Prefix match for /images/\n";
}
# 正则表达式匹配
location ~ \.(png|jpe?g)$ {
return 200 "Regex match for images\n";
}
# 普通前缀匹配
location /documents/ {
return 200 "Longest prefix match for /documents/\n";
}
# 默认匹配
location / {
return 200 "Default match for /\n";
}
}对于请求 http://example.com/images/logo.png,虽然同时匹配了 ^~/images/ 和 \.(png|jpe?g)$,但由于 ^~ 修饰符的存在,会选择第一个匹配项。
proxy_pass 详解
proxy_pass 是 Nginx 反向代理的核心指令,用于将请求转发给后端服务器。
基本用法
location /api/ {
proxy_pass http://backend_server;
}URI 处理规则
proxy_pass 的行为取决于其后是否有 URI 路径:
1. 不带 URI 路径的 proxy_pass
location /api/ {
proxy_pass http://backend; # 注意末尾没有 /
}在这种情况下,请求的完整 URI 会被传递给后端服务器:
- 请求:
http://example.com/api/users/123 - 转发到:
http://backend/api/users/123
2. 带 URI 路径的 proxy_pass
location /api/ {
proxy_pass http://backend/; # 注意末尾有 /
}在这种情况下,location 匹配的部分会被替换为 proxy_pass 指定的 URI:
- 请求:
http://example.com/api/users/123 - 转发到:
http://backend/users/123
实际示例对比
# 示例 1: 不带 URI 路径
location /api/ {
proxy_pass http://backend;
}
# /api/users -> http://backend/api/users
# 示例 2: 带 URI 路径
location /api/ {
proxy_pass http://backend/;
}
# /api/users -> http://backend/users
# 示例 3: 精确匹配
location = /api {
proxy_pass http://backend;
}
# /api -> http://backend/api
# 示例 4: 前缀匹配不以 / 结尾
location /api {
proxy_pass http://backend/;
}
# /api -> http://backend//
# /api/users -> http://backend//users反向代理常用配置
基本代理头设置
location /api/ {
proxy_pass http://backend/;
# 传递真实的主机名
proxy_set_header Host $host;
# 传递真实的客户端 IP
proxy_set_header X-Real-IP $remote_addr;
# 传递完整的代理链 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 传递使用的协议 (http/https)
proxy_set_header X-Forwarded-Proto $scheme;
}超时和缓冲配置
location /api/ {
proxy_pass http://backend/;
# 连接超时时间
proxy_connect_timeout 30s;
# 发送超时时间
proxy_send_timeout 30s;
# 读取超时时间
proxy_read_timeout 30s;
# 启用响应缓冲
proxy_buffering on;
# 缓冲区大小
proxy_buffer_size 4k;
proxy_buffers 8 4k;
# 临时文件最大大小
proxy_max_temp_file_size 1024m;
}负载均衡配置
# 定义上游服务器组
upstream backend {
server 192.168.1.10:8080 weight=3;
server 192.168.1.11:8080;
server 192.168.1.12:8080 backup;
}
location /api/ {
proxy_pass http://backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}高级代理技巧
条件代理
location /api/ {
# 根据请求方法进行不同处理
if ($request_method = POST) {
proxy_pass http://write_backend;
break;
}
proxy_pass http://read_backend;
}动态代理
location /proxy/ {
# 从 URI 中提取目标地址
rewrite ^/proxy/(.*)$ /$1 break;
proxy_pass http://$1;
}错误处理
location /api/ {
proxy_pass http://backend/;
# 自定义后端错误页面
proxy_intercept_errors on;
error_page 500 502 503 504 /backend_error.html;
}实际应用场景
微服务网关配置
upstream user_service {
server 192.168.1.10:3000;
}
upstream order_service {
server 192.168.1.11:3000;
}
upstream product_service {
server 192.168.1.12:3000;
}
server {
listen 80;
server_name api.example.com;
# 用户服务
location /api/users/ {
proxy_pass http://user_service/;
proxy_set_header Host $host;
}
# 订单服务
location /api/orders/ {
proxy_pass http://order_service/;
proxy_set_header Host $host;
}
# 产品服务
location /api/products/ {
proxy_pass http://product_service/;
proxy_set_header Host $host;
}
# 默认服务
location / {
return 404 "API endpoint not found";
}
}WebSocket 代理
location /ws/ {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}文件上传代理
location /upload/ {
proxy_pass http://file_backend/;
# 增加客户端最大 body 大小限制
client_max_body_size 100m;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}调试技巧
查看匹配结果
location /test {
add_header X-Location-Match "Matched /test";
return 200 "Location matched\n";
}记录代理信息
location /api/ {
proxy_pass http://backend/;
# 在日志中记录代理信息
log_format proxy '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"Proxy to: $upstream_addr" "Response time: $upstream_response_time"';
access_log /var/log/nginx/proxy.log proxy;
}最佳实践
1. 明确的匹配规则
# 好的做法:明确指定匹配类型
location = /favicon.ico {
# 精确匹配 favicon
}
location ^~ /static/ {
# 静态资源,不需要正则匹配
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
# 正则匹配静态资源
}2. 合理的代理配置
location /api/ {
proxy_pass http://backend/;
# 必要的代理头
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 合理的超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
# 启用缓冲提高性能
proxy_buffering on;
}总结
掌握 location 匹配规则和 proxy_pass 的使用是精通 Nginx 的关键步骤。通过合理配置,我们可以实现:
- 精确的请求路由
- 高效的反向代理
- 灵活的负载均衡
- 安全的微服务网关
在下一章中,我们将探讨 HTTPS 配置和安全加固的相关内容,帮助你构建更加安全可靠的 Web 服务。
要点回顾:
- location 匹配有四种类型,优先级依次为 = > ^~ > ~,~* > 无修饰符
- proxy_pass 是否带有 URI 路径会影响 URI 的处理方式
- 正确设置代理头对于后端服务识别真实客户端信息至关重要
- 合理配置超时和缓冲参数可以提高代理性能