Nginx Location 加不加 / 的问题
近期在配置Nginx的时候,总是晕这个 Location /
如何去配置,怎么配置访问到什么,怎么配置才是正确的,每次都要纠结一下,所以这次我干脆搭建一个后端接收Nginx反向代理,然后输出真实请求路径。
(English version translate by GPT-3.5)
最近项目的确碰到蛮多用nginx的地方,但是nginx这个 location /xxx
的问题着实头痛,虽然网上资料一堆,但是每次去查下还不一定直接选到最适合自己的,还不如自己写一份呢。
在Nginx的官网中也有详细介绍 Module ngx_http_proxy_module - nginx.org,下面开始,文中的 上面
指代 Location部分,而 下面
指的是proxy_pass部分
常规请求
这个请求没啥好说的,就是进来啥就转发到啥
1 | location / { |
测试1
1 | 请求:http://127.0.0.1:9999/path1/path2/path3/maven2/io/netty/netty.jar |
包括这样子配置也是一样的
1 | location /test { |
测试2
1 | 请求:http://127.0.0.1:9999/test/netty.jar |
这句话在官网解释如下
If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI
即,如果proxy_pass中没有定义URI,那么请求的地址将完整的传给后端,所以如果只是将 /api
请求到后端的 /api
,这样配置就行
1 | location /api { |
两边都带 /
在这个情况下,请求会将/test/去掉,直接将后面都URL请求到后端,如下所示
1 | location /test/ { |
在官网中有这句话
If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive
如果 proxy_pass
是用一个URI指定的,那么当请求传递到后端时,与这个位置匹配的规范化请求地址将会被指令中指定的URL替换。。。呃,我语文时不及格的。。。反正就是多试几个感受下
测试1 前短后长
1 | location /test/ { |
测试2 前长后短
1 | location /private/maven-repo/maven2/ { |
测试3 前长后稍长
1 | location /private/maven-repo/maven2/ { |
结论
从上面2个测试中,它说的指令就是下面的proxy_pass中的URL,2边都带 /
的请求,就会将上面 location /xxxxx/yyy/
中的 /xxxxx/yyy/
给全部替换掉,替换成下面proxy_pass的地址后面的所有路径,例如上面 location /private/maven-repo/maven2/
转发到 http://127.0.0.1:8000/maven-repo/
, 它就会将 /private/maven-repo/
给替换成 /maven-repo/
然后请求到后端
含Path且上面带 /,下面不带 /
与常规不同,这里下面不带 / 指的是含path的情况,根据上面这一个测试,应该能得出结论了
1 | location /private/maven-repo/maven2/ { |
按照上面的逻辑,它就是直接把 /private/maven-repo/maven2/
给替换成了 /maven-repo/central
,然后请求到后端,这里可能就会出现拼接后的地址被合并的情况。
含Path,上面不带/,下面带/,以及上下都不带 /
这其实也是可以按照上面的逻辑完成
测试1,上面不带 / 下面带 /
1 | location /private/maven-repo/maven2 { |
测试2,上面下面都不带 /
1 | location /private/maven-repo/maven2 { |
果然也是一个替换过程,对于上面带/下面不带/,就是将 /private/maven-repo/maven2
替换成了 /maven-repo/central/
,然后直接加上后面的参数,就变成了 /maven-repo/central//io/netty.jar
的情况,对于2边都不带 / 的情况,就是将 /private/maven-repo/maven2
替换成了 /maven-repo/central
。
所以说,如果只有一个 / 的情况下,那么它将会这样请求
1 | location / { |
总结
其实上述测试中,就2个情况,直接地址代理和自动替换方式
当proxy_pass里面直接填上Host,后面没有任何路径时,请求进来的是什么,就会给后端发什么
1
2location /aa/bb -> 请求 /aa/bb/cc.jar
后端地址:/aa/bb/cc.jar如果proxy_pass添加了任何Host,并没有任何参数时,那么会将location 后面的所有内容替换成proxy_pass的URL地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30情况一
location /jcenter/maven2/
proxy_pass https://jcenter.bintray.com/
会将请求中的 /jcenter/maven2/ 替换成 /
例如 /jcenter/maven2/io/netty.jar 会请求到 https://jcenter.bintray.com/io/netty.jar
情况二
如果location 结尾没有 /,但是proxy_pass后面有 /,就会出现 // 的情况
location /jcenter/maven2
proxy_pass https://jcenter.bintray.com/
请求:/jcenter/maven2/io/netty.jar
首先将 /jcenter/maven2 替换成 /,然后拼接后面的内容,实际请求就变成了
https://jcenter.bintray.com//io/netty.jar
情况三
这个情况对于location中结尾有/,proxy_pass没有 / 结果是一样的
location /maven2/
proxy_pass https://repo1.apache.org/maven2
对于请求 /maven2/io/netty.jar
按照规则将 /maven2/ 替换成/maven2, 然后拼接后面的字符,就变成了
https://repo1.apache.org/maven2io/netty.jar
情况四,与情况2类似,就是都是有 / 的情况下
这个情况对于location中结尾有/,proxy_pass也有 / 结果和情况2是一样的
location /maven2/
proxy_pass https://repo1.apache.org/maven/maven2/
对于请求 /maven2/io/netty.jar
按照规则将 /maven2/ 替换成/maven/maven2/, 然后拼接后面的字符io/netty.jar,就变成了
https://repo1.apache.org/maven/maven2/io/netty.jar
但是这里如果请求 /maven2,就会出现自动加 / 的问题,这个自行查阅下吧,很容易理解的。(server_name_in_redirect以及port_in_redirect以及absolute_redirect,知道这3个,就知道怎么解决了。)