为什么变量在 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
的连接确实在发出请求时发生,表明变量 do 在 proxy-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,因此它变得更加复杂。特别的兴趣点是:
- 添加带有集群 DNS 服务 IP 的
resolver
指令(在我的例子中是 10.43.0.10)。这是 kube-system
namespace. 中 kube-dns
服务的 ClusterIP
- 即使您的 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/
向上游传递并中断。
为什么变量在 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
的连接确实在发出请求时发生,表明变量 do 在 proxy-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,因此它变得更加复杂。特别的兴趣点是:
- 添加带有集群 DNS 服务 IP 的
resolver
指令(在我的例子中是 10.43.0.10)。这是kube-system
namespace. 中 - 即使您的 NGINX 同名也请使用 FQDNspace,因为 DNS 显然只能解析 FQDN。
kube-dns
服务的 ClusterIP
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/
向上游传递并中断。