在某些情况下,$sent_http_ 变量在 Nginx 中消失

在某些情况下,$sent_http_ 变量在 Nginx 中消失

我在使用 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_typevar,而只是读取。

它看起来$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" "";
    "~^(?<_>.+)$" "$_";
}

相关内容