Nginx根据一个请求执行两个位置

Nginx根据一个请求执行两个位置,nginx,nginx-reverse-proxy,nginx-location,nginx-ingress,Nginx,Nginx Reverse Proxy,Nginx Location,Nginx Ingress,具有以下nginx配置 server { listen 2022; location /STFlow/ { rewrite ^/STFlow(.*)$ $1 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-Fo

具有以下nginx配置

server {
  listen 2022;
  location /STFlow/ {
    rewrite ^/STFlow(.*)$ $1 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 $1;
    }
    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;
  }
执行
curlhttp://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和okd的不速之客。在我看来,好像从/STFlow/和/两个位置都执行了重写

据我所知,nginx文档只应选择并执行一个位置

但在这里我们可以看到两种匹配:

“^/STFlow(.*)”匹配“/STFlow/仪表板”

它似乎来自
位置/STFlow/
和更高版本

^(\d+。\d+。\d+。\d+)匹配“10.221.196.254” 这似乎来自
位置/

怎么可能呢

这是怎么回事

是否可以在这两个位置放置一些自定义调试日志,以查看哪些行被执行以及执行的顺序

据我所知,nginx文档只应选择并执行一个位置

实际上,只选择一个位置来服务请求。这并不意味着在到达最终位置时,不会在位置(上下文)之间进行“跳跃”

这就是重写模块实际负责的:通过重写当前URI在上下文之间跳跃/基于重写的URI重复NGINX的位置搜索

NGINX首先查找前缀最长的
位置
,用于服务请求。具体到您的示例,这是
location/STFlow/{
。现在它选择它进行评估

它看到
rewrite^/STFlow(.*)$$1 last;
将当前URI修改为
/dashboard
last
关键字to
rewrite
指令会根据当前
/dashboard
URI再次触发位置搜索。值得注意的是,在跳过
位置/STFlow/{
location/{
前者的指令将不适用。在“跳转”之后,现在
location/{
是当前选择用于服务请求的指令,等等

位置/{/code>没有更多的指令(没有
try_文件
重写
,等等)可以修改当前URI并再次触发搜索。因此,它是NGINX用于构建响应的最终位置

如果最终位置是嵌套位置,则最终应用于服务响应的指令/配置是来自最终位置或其父位置的指令/配置。即使如此,它也取决于特定的指令。有些指令将从父位置继承,有些则不会。这是它自己的一个主要主题。 例如:

location / {
    expires max;
    location /foo/ {
       index index.php;   
    }
}
expires
将申请对
/foo/bar
的请求,因为它属于嵌套位置
/foo/
。 但如果要使其非嵌套:

location / {
   expires max;
}
location /foo/ {
   index index.php;   
}
expires
将不适用于URI
/foo/bar

类似数组的指令,例如
fastcgi_param
add_header
等,从父位置继承的方式与直觉相反。只有当它们不在嵌套位置时,才会被继承

使用此配置,仅设置了
X-Something:1;
,但如果要注释掉它的行,则将应用父标题,并在输出标题中查看
X-Foo:Bar

有些人可能会称之为“糟糕的设计”,因为它在开始时会导致很多混乱。

:

break、if、return、rewrite和set指令按以下顺序处理:

在服务器级指定的ngx_http_rewrite_module指令顺序执行

反复

  • 根据请求URI搜索位置
  • 在找到的位置内指定的该模块的指令按顺序执行
  • 如果请求URI被重写,则重复循环n,但不会更多 超过10倍

thx感谢您的回复,这非常有帮助。有一件事我仍然不明白,为什么日志中没有一行关于匹配第二个“位置/”的内容?有什么解释吗?我相信在配置的某个地方,您已经通过
rewrite\u log on;
激活了rewrite log。这将打开rewrite模块的日志记录。位置匹配是NGINX本身的核心。您可能可以通过
为头设置不同的值来调试选择的位置>添加_头
(但请注意上面提到的关于继承的陷阱),然后通过
curl
检查响应头。
location / {
    add_header X-Foo Bar;
    location /foo/ {
        add_header X-Something 1; 
    }
}