我在使用 Nginx 时遇到了一个奇怪的问题。这是重现错误的最小配置:
server {
server_name mydomain.com;
listen 111.111.111.111:80;
root /some/path;
set $some_var $sent_http_content_type;
add_header "X-Debug" $sent_http_content_type;
}
在这种情况下,X-Debug
响应中永远不会显示标头。但是,如果我注释掉此行:
set $some_var $sent_http_content_type;
一切正常。这对我来说似乎很奇怪,因为这行没有重新分配$sent_http_content_type
var,而只是读取。
它看起来$sent_http_
只属于变量。
我也尝试过"${sent_http_content_type}"
,$sent_http_content_type
结果相同。
more_set_headers
指令没有修复这个问题。
Nginx 为什么会出现这种情况?这是一个 bug 吗?
编辑:
我提供的示例只是$sent_http_
vars 消失的最简单的情况。实际上,我想做这样的事情:
if ($sent_http_access_control_allow_origin ~ "^(https?)://([^/]+)") {
set $new_cors http://$1.$2.proxy.mydomain.com;
}
more_set_headers "Access-Control-Allow-Origin: $new_cors";
我编写了一个代理服务器,我需要替换Access-Control-Allow-Origin
响应标头,因为否则代理站点无法按预期工作。
在上面的示例if
条件(在部分中)中,即使有这样的标题并且它符合我的正则表达式,server
也不会产生。true
这个问题能修复吗?非常感谢您的帮助!
答案1
Nginx 的rewrite
模块(变量和set
指令所属的地方)相当不直观且脆弱。但实际上
set $some_var $sent_http_content_type;
无论如何都是没有意义的,因为指令是在请求开始时执行的,并且目前set
没有可用的变量。$sent_http_*
您可以做的(如果您确实想以$sent_http_*
某种方式使用变量)是使用map
指令。
map $sent_http_content_type $some_var {
default $sent_http_content_type;
}
...
server {
...
add_header "X-Debug" $sent_http_content_type;
add_header "X-Debug2" $some_var;
}
编辑:您的问题可以通过更多的 s 来解决map
,但如果您可以使用 Lua 模块,那就容易多了。
这里是如何用 s 来实现的map
:(非常难以阅读和维护)
map $sent_http_access_control_allow_origin $__proto {
default "NONE";
"~^(?<_>https?):" "$_";
}
map $sent_http_access_control_allow_origin $__host {
default "";
"~^https?://(?<_>[^/]+)" "$_";
}
map "http://$__proto.$__host.proxy.mydomain.com" $new_cors {
default "";
"~^http://NONE" "";
"~^(?<_>.+)$" "$_";
}