说到Nginx实现虚拟路径代理,就必须要使用proxy_pass模块了,下面先给一些proxy_pass比较官方的解释,说实话理解起来是有些费劲的,需要多多测试才能掌握。
一、proxy_pass
1 2 3 |
Syntax: proxy_pass URL; Default:— Context:location, if in location, limit_except |
设置后端服务器的协议和地址,还可以设置可选的URI以定义本地路径和后端服务器的映射关系。 这条指令可以设置的协议是“http”或者“https”,而地址既可以使用域名或者IP地址加端口(可选)的形式来定义:
1 |
proxy_pass http://localhost:8000/uri/; |
对于URI可选,一般情况下使用是不需要指定的,除非你需要的访问方式就是这样的。
也可以使用UNIX域套接字路径来定义,该路径接在“unix”字符串后面,两端由冒号所包围,比如:
1 |
proxy_pass http://unix:/tmp/backend.socket:/uri/; |
如果proxy_pass没有使用URI,传送到后端服务器的请求URI一般客户端发起的原始URI,如果nginx改变了请求URI,则传送的URI是nginx改变以后的完整规范化URI:
1 2 3 |
location /path/ { proxy_pass http://127.0.0.1; } |
如果proxy_pass使用了URI(/也算),当传送请求到后端服务器时,规范化以后的请求路径(原始请求URI)与location配置中的路径的匹配部分将被替换为proxy_pass指令中定义的URI,其实这种实现方式就是做虚拟路径代理,配置方式如下:
1 2 3 |
location /path/ { proxy_pass http://127.0.0.1/; } |
虚拟路径代理就是,比如说访问”http://127.0.0.1/path/uri”地址,当匹配到这个location之后,通过”proxy_pass http://127.0.0.1/”代理到后端时,一个新的URL就成了”http://127.0.0.1/uri”这样。其中的/path就称为虚拟路径,虚拟给用户的,后端没有真正的/path路径,这里要特别注意”proxy_pass http://127.0.0.1/”最后的”/”,如果没有这个”/”那么访问就会出现404,因为你没有给proxy_pass定义URI,所以不存在将规范化以后的请求路径(原始请求URI)与location配置中的路径的匹配部分将被替换为proxy_pass指令中定义的URI这一说法,切记。Nginx实现虚拟路径代理
注意
当使用一个正则表达式(~或~*)指定localtion时,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path,也就是说原始访问URI不会做任何改变传送到后端。
还有一种情况,当URI使用rwrite重写指令后,在这种情况下,proxy_pass应该是一个没有URI的指令,如果指定了URI,那么代理到后端时,URI会被去掉,从而变成了http://127.0.0.1/some/path。
1 |
rewrite /name/([^/]+) /users?name=$1 break; |
二、虚拟路径案例
现在有这么一个后台,需要前端做一个代理,需要在其他域名做一个虚拟URI代理到这个后台,这样后台地址是不真正对外暴露的。
先通过IP访问这个后台是没有问题的,如下图:
在要代理的域名上面配置一个虚拟路径访问,叫/crm-web,先配置一个location匹配/crm-web,然后通过proxy_pass代理到后端。
1 2 3 4 5 6 7 |
location /crm-web/ { proxy_pass http://10.100.156.173:8300/; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } |
这里需要注意,配置虚拟路径访问就涉及到了在proxy_pass部分讲的:如果proxy_pass使用了URI(/也算),当传送请求到后端服务器时,规范化以后的请求路径(原始请求URI)与location配置中的路径的匹配部分将被替换为proxy_pass指令中定义的URI。
因此可以明白这里”proxy_pass http://10.100.156.173:8300/”最后为什么有”/”了,就是要把原始访问/crm-web/
替换成/
,这样到后端就成了直接访问http://10.100.156.173:8300/
了,也就没有任何问题了。
访问看看效果
根据图可以看到没有问题了,但是有些静态资源访问报错了。看一下静态资源的访问地址(程序中写死的静态访问地址),可以发现这是浏览器发起的访问请求,由于没有/crm-web路径,所以自然没有匹配到我们定义的location(默认应该匹配到root指定的路径下了)。
所以我们可以再加一个匹配/static的location,还是代理到这个地址,location配置如下:
1 2 3 4 5 6 7 |
location ^~ /static/ { proxy_pass http://10.100.156.173:8300; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } |
但是需要注意与当一个location不同的是,”proxy_pass http://10.100.156.173:8300″后面没有加”/”,因为我们需要把/static传递到”http://10.100.156.173:8300″后面发送给后端服务器请求数据,最后构造成的URI就是”http://10.100.156.173:8300/static”。
再次访问试试看效果
完美搞定。。。
有时候我们的 location 是这样写的 /crm-web/,有时候是 /crm-web 写的,两者的区别就是看被代理端的需求,举个代理 elastic 的例子:
1 2 3 |
location /elastic { proxy_pass http://127.0.0.1:9200/; } |
这里会把 /elastic
替换成 /
,可以正常访问 ES 的 index 页面。但是想查看集群节点,正常我们访问路径是 /_cat/nodes,通过代理之后我们访问 URI 如 /elastic/_cat/nodes,这里会替换成 //_cat/nodes,自然访问就会报错。
这里有两种办法,把 location /elastic 替换成 location /elastic/,如下:
1 2 3 |
location /elastic/ { proxy_pass http://127.0.0.1:9200/; } |
这样当我们访问 /elastic/_cat/nodes 时,就会替换为 /_cat/nodes,访问正常。
或者,直接访问 /elastic_cat/nodes,同样会替换为 /_cat/nodes,访问正常。