Nginx

$sent_http_ 變數在某些情況下會在 Nginx 中消失

  • March 1, 2016

我在 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 會有這樣的行為?這是一個錯誤嗎?

編輯:
我提供的範例只是$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,即使有這樣的標題並且它符合我的正則表達式,它也永遠不會產生。

這可以解決嗎?感謝你的幫助!

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;
}

編輯:你的問題可以用更多map的 s 來解決,但如果你可以使用 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" "";
   "~^(?<_>.+)$" "$_";
}

引用自:https://serverfault.com/questions/760569