Nginx 两个位置在一个请求上执行
Nginx two locations executed on one request
使用以下 nginx 配置
server {
listen 2022;
location /STFlow/ {
rewrite ^/STFlow(.*)$ last;
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
}
location / {
set $realip $remote_addr;
if ($http_x_forwarded_for ~ "^(\d+\.\d+\.\d+\.\d+)") {
set $realip ;
}
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
client_max_body_size 50M;
}
随着执行
curl http://okd-dev-route.internal.com/STFlow/dashboard
我得到以下日志:
2020/07/16 07:38:39 [notice] 31#31: *1 "^/STFlow(.*)$" matches "/STFlow/dashboard", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 rewritten data: "/dashboard", args: "", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 "^(\d+\.\d+\.\d+\.\d+)" matches "10.221.196.254", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [info] 31#31: *1 client 10.129.4.1 closed keepalive connection (104: Connection reset by peer)
我是 nginx 的新手,还不错。它看起来好像从两个位置 /STFlow/ 和 / 执行了重写!
据我了解 nginx 文档只有一个位置应该被选择和执行。
但是在这里我们可以看到两个匹配项:
"^/STFlow(.*)$" matches "/STFlow/dashboard"
这似乎来自 location /STFlow/
及之后的
"^(\d+.\d+.\d+.\d+)" matches "10.221.196.254"
which seems to come from if condition in location /
怎么可能?
这是怎么回事?
是否可以在两个位置放置一些自定义调试日志以查看执行了哪些行以及执行顺序?
As far as I understood nginx documentation only one location should be selected and executed
确实只选择了一个位置用于服务请求。这并不意味着在到达最终位置时没有在位置(上下文)之间进行“跳跃”。
rewrite模块实际负责的是:通过重写当前URI在上下文之间跳转/根据重写的URI重复NGINX的位置搜索。
NGINX 首先为服务请求找到前缀最长的 location
。具体到你的例子,这是location /STFlow/ {
。现在就选它来评测了。
它看到 rewrite ^/STFlow(.*)$ last;
将当前 URI 修改为 /dashboard
。 last
关键字到 rewrite
指令会根据当前的 /dashboard
URI 再次触发位置搜索。值得注意的是,在跳转 location /STFlow/ {
到 location / {
时,前者的指令将不适用。 “跳转”之后,现在 location / {
是当前为请求服务而选择的那个
location / {
没有更多指令(没有try_files
、rewrite
等)可以修改当前URI并重新触发搜索。因此,它是 NGINX 用于构建响应的最终位置。
最终将应用于服务响应的 directives/configuration 是来自最终位置 或其 parent 的 if 最终位置是一个嵌套位置。即使那样,它也取决于特定的指令。有些指令将从 parent 位置继承,有些则不会。它本身就是一个重要的话题。
例如:
location / {
expires max;
location /foo/ {
index index.php;
}
}
expires
将向 /foo/bar
申请请求,因为它属于嵌套位置 /foo/
。
但如果你要做到 non-nested:
location / {
expires max;
}
location /foo/ {
index index.php;
}
expires
将不适用于 URI /foo/bar
。
Array-like 指令,例如fastcgi_param
、add_header
等从 parent 位置继承的方式是 counter-intuitive。它们被继承仅当它们不存在于嵌套位置。
location / {
add_header X-Foo Bar;
location /foo/ {
add_header X-Something 1;
}
}
使用此配置,仅设置 X-Something: 1;
,但如果您要注释掉它的行,您将应用 parent header 并在中查看 X-Foo: Bar
输出 headers.
有些人可能会称之为“糟糕的设计”,因为它在开始时会导致很多混乱。
Here is the explanation of my problem:
break、if、return、rewrite 和 set 指令按以下顺序处理:
服务器级别指定的ngx_http_rewrite_module模块指令按顺序执行;
反复:
- 根据请求 URI 搜索 位置;
- 在找到的位置内指定的该模块的指令按顺序执行;
- 如果请求 URI 被重写n,则重复循环,但不会更多
超过10次。
使用以下 nginx 配置
server {
listen 2022;
location /STFlow/ {
rewrite ^/STFlow(.*)$ last;
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
}
location / {
set $realip $remote_addr;
if ($http_x_forwarded_for ~ "^(\d+\.\d+\.\d+\.\d+)") {
set $realip ;
}
proxy_pass http://zuul-proxy:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;
client_max_body_size 50M;
}
随着执行
curl http://okd-dev-route.internal.com/STFlow/dashboard
我得到以下日志:
2020/07/16 07:38:39 [notice] 31#31: *1 "^/STFlow(.*)$" matches "/STFlow/dashboard", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 rewritten data: "/dashboard", args: "", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [notice] 31#31: *1 "^(\d+\.\d+\.\d+\.\d+)" matches "10.221.196.254", client: 10.129.4.1, server: , request: "GET /STFlow/dashboard HTTP/1.1", host: "okd-dev-route.internal.com"
2020/07/16 07:38:39 [info] 31#31: *1 client 10.129.4.1 closed keepalive connection (104: Connection reset by peer)
我是 nginx 的新手,还不错。它看起来好像从两个位置 /STFlow/ 和 / 执行了重写!
据我了解 nginx 文档只有一个位置应该被选择和执行。
但是在这里我们可以看到两个匹配项:
"^/STFlow(.*)$" matches "/STFlow/dashboard"
这似乎来自 location /STFlow/
及之后的
"^(\d+.\d+.\d+.\d+)" matches "10.221.196.254" which seems to come from if condition in
location /
怎么可能?
这是怎么回事?
是否可以在两个位置放置一些自定义调试日志以查看执行了哪些行以及执行顺序?
As far as I understood nginx documentation only one location should be selected and executed
确实只选择了一个位置用于服务请求。这并不意味着在到达最终位置时没有在位置(上下文)之间进行“跳跃”。
rewrite模块实际负责的是:通过重写当前URI在上下文之间跳转/根据重写的URI重复NGINX的位置搜索。
NGINX 首先为服务请求找到前缀最长的 location
。具体到你的例子,这是location /STFlow/ {
。现在就选它来评测了。
它看到 rewrite ^/STFlow(.*)$ last;
将当前 URI 修改为 /dashboard
。 last
关键字到 rewrite
指令会根据当前的 /dashboard
URI 再次触发位置搜索。值得注意的是,在跳转 location /STFlow/ {
到 location / {
时,前者的指令将不适用。 “跳转”之后,现在 location / {
是当前为请求服务而选择的那个
location / {
没有更多指令(没有try_files
、rewrite
等)可以修改当前URI并重新触发搜索。因此,它是 NGINX 用于构建响应的最终位置。
最终将应用于服务响应的 directives/configuration 是来自最终位置 或其 parent 的 if 最终位置是一个嵌套位置。即使那样,它也取决于特定的指令。有些指令将从 parent 位置继承,有些则不会。它本身就是一个重要的话题。 例如:
location / {
expires max;
location /foo/ {
index index.php;
}
}
expires
将向 /foo/bar
申请请求,因为它属于嵌套位置 /foo/
。
但如果你要做到 non-nested:
location / {
expires max;
}
location /foo/ {
index index.php;
}
expires
将不适用于 URI /foo/bar
。
Array-like 指令,例如fastcgi_param
、add_header
等从 parent 位置继承的方式是 counter-intuitive。它们被继承仅当它们不存在于嵌套位置。
location / {
add_header X-Foo Bar;
location /foo/ {
add_header X-Something 1;
}
}
使用此配置,仅设置 X-Something: 1;
,但如果您要注释掉它的行,您将应用 parent header 并在中查看 X-Foo: Bar
输出 headers.
有些人可能会称之为“糟糕的设计”,因为它在开始时会导致很多混乱。
Here is the explanation of my problem:
break、if、return、rewrite 和 set 指令按以下顺序处理:
服务器级别指定的ngx_http_rewrite_module模块指令按顺序执行;
反复:
- 根据请求 URI 搜索 位置;
- 在找到的位置内指定的该模块的指令按顺序执行;
- 如果请求 URI 被重写n,则重复循环,但不会更多 超过10次。