1.proxy_pass使用
proxy_pass指令用于请求的转发,请客户端请求转发至第三方服务器;如下所示:
location /query {
proxy_pass http://www.baidu.com;
}
上述案例将以/query开头的url请求转发至http://www.baidu.com.
proxy_pass用法较为简单,但使用时路径拼接问题需要重点关注,也是本章节的重点,以下通过案例的方案进行介绍和验证。
基准用例准备:
说明:路径拼接问题出现在前缀匹配上,完全匹配和正则表达式匹配不存在该问题。因此,可以借助完全匹配作为基准测试用例。
在8888端口上监听四个完全匹配路径:
server {
server_name localhost;
listen 8888;
location = /test.html {
return 200 "enter /test.html ";
}
location = /proxy/test.html {
return 200 "enter /proxy/test.html ";
}
location = /ewen/test.html {
return 200 "enter /ewen/test.html ";
}
location = /ewentest.html {
return 200 "enter /ewentest.html ";
}
}
测试结果如下所示:
[root@124 conf]# curl http://localhost:8888/test.html
enter /test.html
[root@124 conf]# curl http://localhost:8888/proxy/test.html
enter /proxy/test.html
[root@124 conf]# curl http://localhost:8888/ewen/test.html
enter /ewen/test.html
[root@124 conf]# curl http://localhost:8888/ewentest.html
enter /ewentest.html
问题来源:
location /代理url部分 {
proxy_pass http://目标url部分
}
代理url部分
是否以/结尾,以及目标url是否携带子路径和是否已/结尾等因素,可以将
location /proxy {proxy_pass http://localhost:8888;}`组合形成8种场景:
#case1: 代理url部分不以/结尾,目标url没有子路径且不以/结尾
location /proxy {
proxy_pass http://localhost:8888;
}
#case2: 代理url部分不以/结尾,目标没有子路径且url以/结尾
location /proxy {
proxy_pass http://localhost:8888/;
}
#case3: 代理url部分以/结尾,目标url没有子路径且不以/结尾
location /proxy/ {
proxy_pass http://localhost:8888;
}
#case4: 代理url部分以/结尾,目标url没有子路径,以/结尾
location /proxy/ {
proxy_pass http://localhost:8888/;
}
#case5: 代理url不以/结尾,目标url存在子路径且不以/结尾
location /proxy {
proxy_pass http://localhost:8888/ewen;
}
#case6: 代理url不以/结尾,目标url存在子路径且以/结尾
location /proxy {
proxy_pass http://localhost:8888/ewen/;
}
#case7: 代理url以/结尾,目标url存在子路径且不以/结尾
location /proxy/ {
proxy_pass http://localhost:8888/ewen;
}
#case8: 代理url以/结尾,目标url存在子路径且以/结尾
location /proxy/ {
proxy_pass http://localhost:8888/ewen/;
}
当执行http://localhost:8001/proxy/test.html
请求后,上述8种情况的访问路径为:
http://localhost:8888 | http://localhost:8888/ | http://localhost:8888/ewen | http://localhost:8888/ewen/ | |
---|---|---|---|---|
/proxy/ | http://localhost:8888/proxy/test.html | http://localhost:8888/test.html | http://localhost:8888/ewentest.html | http://localhost:8888/ewen/test.html |
/proxy | http://localhost:8888/proxy/test.html | http://localhost:8888/test.html | http://localhost:8888/ewen/test.html | http://localhost:8888/ewen//test.html |
结论:
[1] 如果目标url仅包括ip和端口(没有斜线和子路径),如http://localhost:8888形式,则仅替换协议、域名和端口部分,其他路径保持不变:
如上述案例中:
location /proxy/ {
proxy_pass http://localhost:8888;
}
和
location /proxy {
proxy_pass http://localhost:8888;
}
场景下,访问http://localhost:8001/proxy/test.html
都会转发到http://localhost:8888/proxy/test.html
[2] 其他场景,客户端的请求的url路径删除协议-域名-端口后,进行代理url的剪切,将剪切后的部分直接拼接到目标url尾部,以下以案例进行过程说明。
访问http://localhost:8001/proxy/test.html时:
如果location定义为:
location /proxy {
proxy_pass http://localhost:8888/ewen;
}
http://localhost:8001/proxy/test.html删除协议-域名-端口部分后,得到/proxy/test.html;
/proxy/test.html 删除代理url后,得到/test.html;
/test.html拼接至目标url即http://localhost:8888/ewen后,得到http://localhost:8888/ewen/test.html.
如果location定义为:
location /proxy/ {
proxy_pass http://localhost:8888/ewen;
}
http://localhost:8001/proxy/test.html删除协议-域名-端口部分后,得到/proxy/test.html;
/proxy/test.html 删除代理url后,得到test.html;
test.html拼接至目标url即http://localhost:8888/ewen后,得到http://localhost:8888/ewentest.html.