为什么变量在 NGINX `proxy_pass` 中不起作用?

Why does a variable not work in NGINX `proxy_pass`?

为什么变量在 proxy_pass 中不起作用?

这非常有效:

location /foo/ {
  proxy_pass http://127.0.0.1/;
}

这根本行不通:

location /foo/ {
  set $FOO http://127.0.0.1/;
  proxy_pass $FOO;
  add_header x-debug $FOO;
}

我看到了 x-header: http://127.0.0.1/,但结果是 404,所以我不知道它代理到哪里,但它与第一​​个例子不一样。

Source 其中解释了在 proxy_pass 中使用变量将在上游不可用时防止 NGINX 启动错误。

更新:问题是上游路径重写。我希望它在 /blah 处将 /foo/blah 重写到上游,删除 /foo 前缀。它适用于静态 host/uri 条目但不适用于变量。

nginx.conf 中变量的想法是延迟评估。解析 nginx.conf 配置有两个不同的原因:启动时和稍后发出请求时。在第二次解析中,填写了request-dependent个变量。

这个解析器不是很聪明,官方也没有指定这个行为。您 link 中的技巧是一个正确的 hack。

我在生产中使用的work-around是proxy-pass http://$FOO。文字串 http 和变量 $FOO 的连接确实在发出请求时发生,表明变量 doproxy-pass 中起作用。我不知道为什么它不能用简单的替代品工作。由于这是一个未记录的 hack,这可能会因版本而异。如果nginx本身再聪明一点就好了。

[编辑]

In some cases, the part of a request URI to be replaced cannot be determined: ... When variables are used in proxy_pass: location /name/ { proxy_pass http://127.0.0.1$request_uri;} In this case, if URI is specified in the directive, it is passed to the server as is, replacing the original request URI.

手册中详细说明了存在变量时的这种不同行为。您可以尝试 rewrite 指令,它修改要发送的 URI。

在@MSalters 的大力帮助下,最终答案比我想象的要复杂。原因是 NGINX 对变量的处理方式与静态输入的主机名不同——它甚至不使用相同的 DNS 机制。

主要问题是路径处理和前缀剥离对变量的作用不同。您必须自己去除路径前缀。在我原来的例子中:

location /foo/ {
  set $FOO 127.0.0.1;
  rewrite /foo/(.*) / break;
  proxy_pass http://$FOO/$is_args$args;
}

在我的示例中,我使用了 IP 地址,因此不需要解析器。但是,如果您使用主机名,则需要 resolver,因此请在此处添加您的 DNS IP。耸耸肩。

为了全面披露,我们在 Kubernetes 中使用 NGINX,因此它变得更加复杂。特别的兴趣点是:

  1. 添加带有集群 DNS 服务 IP 的 resolver 指令(在我的例子中是 10.43.0.10)。这是 kube-system namespace.
  2. kube-dns 服务的 ClusterIP
  3. 即使您的 NGINX 同名也请使用 FQDNspace,因为 DNS 显然只能解析 FQDN。
location /foo/ {
  set $MYSERVICE myservice.mynamespace.svc.cluster.local;
  rewrite /foo/(.*) / break;
  proxy_pass http://$MYSERVICE/$is_args$args;
  resolver 10.43.0.10 valid=10s;
}

注意:由于 NGINX 中的 BUG(不幸的是,NGINX 维护者未承认),如果路径包含 space,则在 URL 中使用 $1 将会中断。所以 /foo%20bar/ 将作为 /foo bar/ 向上游传递并中断。