Назад | Перейти на главную страницу

Переменные $ 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_type var, но только читает.

Похоже, это принадлежит $sent_http_ только переменные.

Я тоже пробовал "${sent_http_content_type}" вместо того $sent_http_content_type с тем же результатом.

more_set_headers директива не исправляет этого.

Почему Nginx так себя ведет? Это ошибка?

Редактировать:
Приведенный мной пример - это простейший случай, когда $sent_http_ вары исчезают. На самом деле я хочу сделать что-то вроде этого:

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, даже если такой заголовок есть и он подходит моему регулярному выражению.

Это можно исправить? Ценю вашу помощь!

Nginx's 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;
}

РЕДАКТИРОВАТЬ: Ваша проблема может быть решена с помощью еще maps, но было бы намного проще, если бы вы могли использовать модуль Lua.

Вот как это можно сделать с maps: (совершенно нечитаемый и не поддерживаемый)

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