要让第一层Nginx将客户端请求的URL完整透传到第二层Nginx,关键在于正确配置proxy_pass
指令及路径拼接规则。以下是具体配置方法和注意事项:
核心配置原则
proxy_pass
指令末尾是否添加/
会直接影响URL的透传方式:
- 不带
/
:会将location
匹配的路径连同后续URI一起转发 - 带
/
:仅转发location
匹配路径之后的URI(相当于截断匹配路径)
场景1:完整透传所有URL(推荐)
如果希望第一层Nginx将客户端请求的完整URL(包括路径和参数)原封不动地转发到第二层Nginx,配置如下:
第一层Nginx配置
server {
listen 80;
server_name example.com;
# 匹配所有请求(或指定路径,如/location/)
location / {
# 关键:proxy_pass末尾不带/,确保完整透传URL
proxy_pass http://第二层Nginx的IP:端口; # 例如 http://192.168.1.101:8080
# 传递原始请求头(确保第二层能获取完整URL信息)
proxy_set_header Host $host; # 传递客户端访问的域名
proxy_set_header X-Original-URI $request_uri; # 传递完整URI(含参数)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
第二层Nginx配置
server {
listen 8080; # 接收第一层转发的端口
# 直接处理转发过来的完整URL
location / {
# 转发到实际业务服务(如后端API)
proxy_pass http://业务服务IP:端口; # 例如 http://192.168.1.200:8080
# 同样传递头信息(如需业务服务获取原始URL)
proxy_set_header Host $host;
proxy_set_header X-Original-URI $http_x_original_uri; # 传递第一层的原始URI
}
}
场景2:URL路径改写后透传
如果需要在第一层Nginx修改URL路径后再转发(例如添加前缀),可使用rewrite
指令:
第一层Nginx配置(路径改写示例)
server {
listen 80;
server_name example.com;
# 客户端访问 /api/xxx 时,转发到第二层的 /prefix/api/xxx
location /api/ {
# 改写URL路径(在原路径前添加/prefix)
rewrite ^/api/(.*)$ /prefix/api/$1 break;
# 转发到第二层(末尾带/,配合rewrite使用)
proxy_pass http://192.168.1.101:8080;
# 传递头信息
proxy_set_header Host $host;
proxy_set_header X-Original-URI $request_uri; # 保留原始请求的URI
}
}
关键验证方法
测试URL透传是否正确:
使用curl
发送请求并查看第二层Nginx的日志:# 客户端请求 curl http://example.com/path?param=123 # 查看第二层Nginx的access.log,确认日志中的请求路径是否为/path?param=123
检查原始URI:
第二层Nginx可通过$http_x_original_uri
变量获取客户端原始请求的完整URL(需第一层配置X-Original-URI
头)。
常见问题解决
- 路径被截断:若发现URL路径丢失,检查
proxy_pass
末尾是否多了/
,去掉即可完整透传。 - 参数丢失:Nginx默认会透传URL参数,无需额外配置,若参数丢失可能是后端服务处理问题。
- 域名不匹配:确保
proxy_set_header Host $host
配置正确,否则第二层可能因Host不匹配拒绝请求。
通过以上配置,即可实现第一层Nginx到第二层Nginx的URL完整透传,适用于需要多级代理且保留原始请求路径的场景。
rewrite指令
rewrite ^/api/(.*)$ /prefix/api/$1 break;
是 Nginx 中用于 URL 路径改写的核心指令,其作用是将客户端请求的 URL 路径按照指定规则重新改写,再转发到后端服务。下面详细解释其用法和工作原理:
rewrite指令拆解
rewrite
:Nginx 的 URL 重写指令,用于修改请求的 URI 路径。^/api/(.*)$
:正则表达式匹配规则(匹配客户端原始请求路径):^
:表示字符串的开始/api/
:固定匹配以/api/
开头的路径(如/api/user
、/api/order/123
)(.*)
:捕获组,匹配/api/
后面的所有字符(包括子路径和参数),.*
表示任意字符任意长度$
:表示字符串的结束
/prefix/api/$1
:改写后的目标路径:/prefix/api/
:在原始路径前添加的固定前缀$1
:引用前面正则表达式中(.*)
捕获的内容(即/api/
后面的部分)
break
:改写规则的终止标记,意思是“一旦匹配并完成改写,就停止后续的rewrite
规则处理”。
实际效果示例
当客户端请求以下路径时,会被改写成对应的新路径:
客户端原始请求路径 | 改写后的路径(转发给后端) | 说明 |
---|---|---|
/api/user |
/prefix/api/user |
$1 捕获 user |
/api/order/123?type=1 |
/prefix/api/order/123?type=1 |
$1 捕获 order/123?type=1 (含参数) |
/api/v2/product |
/prefix/api/v2/product |
$1 捕获 v2/product |
关键注意事项
与
proxy_pass
配合使用:
该rewrite
指令通常用于location
块中,配合proxy_pass
转发到后端服务。例如:location /api/ { # 先改写路径 rewrite ^/api/(.*)$ /prefix/api/$1 break; # 再转发到后端(注意 proxy_pass 末尾是否带 / 不影响这里的改写结果,因为 rewrite 已处理) proxy_pass http://backend_server; }
break
标记的作用:- 如果用
break
:改写后立即停止后续rewrite
规则,直接用新路径转发。 - 如果用
last
:改写后会重新发起一次请求匹配(可能匹配到其他location
),适合更复杂的多级改写。 - 此处用
break
是最常见的场景,避免重复改写。
- 如果用
不影响客户端可见的 URL:
这种改写是“内部改写”,客户端浏览器地址栏的 URL 不会变化,仅 Nginx 内部转发时使用新路径。参数保留:
原始 URL 中的查询参数(如?type=1
)会被自动保留到改写后的路径中,无需额外配置。
适用场景
- 当后端服务要求路径必须包含特定前缀(如
/prefix/
),但客户端请求的路径没有该前缀时,用于统一添加前缀。 - 实现不同客户端请求路径到后端服务路径的映射(如兼容旧版 API 路径)。
- 配合多级代理时,在第一层 Nginx 统一调整路径后再转发给第二层 Nginx。
通过这个规则,可以灵活地在 Nginx 层面调整请求路径,而无需修改客户端或后端服务的代码。