Nginx で条件付きヘッダーを使用することは不可能ですか?

Nginx で条件付きヘッダーを使用することは不可能ですか?

現在、Nginx を使用して条件付きで CORS ヘッダーのセットのみを返すようにしています。最初は、この動作する構成がすでにあったため、簡単なタスクのように見えました。

upstream api-app {
  server unix:/tmp/api-app.sock fail_timeout=0;
}

server {
  listen 80;
  # [other server stuff...]

  # CORS headers added to all ALL responses of this server (needed for all requests)
  more_set_headers 'Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE,OPTIONS';
  more_set_headers 'Access-Control-Allow-Origin: *';
  more_set_headers 'Access-Control-Allow-Credentials: true';
  more_set_headers 'Access-Control-Request-Method: GET,POST,PATCH,PUT,DELETE,OPTIONS';
  more_set_headers 'Access-Control-Request-Headers: Content-Type';
  more_set_headers 'Access-Control-Allow-Headers: Origin,X-Requested-With,Content-Type,Accept,Session-Id,Role-Id,Visitor-Id,X-Window-Location';
  more_set_headers 'Access-Control-Expose-Headers: X-Total-Entries,X-Total-Pages,X-Page,X-Per-Page,X-Folder-Hierarchy';

  location / {
    # For OPTIONS request only return above headers and no content (also allow caching them)
    if ($request_method = 'OPTIONS') {
      # cache above (Access-Control) headers
      add_header 'Access-Control-Max-Age' 600;

      # set content length and type just for good measure:
      add_header 'Content-Length' 0;
      add_header 'Content-Type' 'text/plain charset=UTF-8';

      # return 204 - no content
      return 204;
    }

    # Forward requests to actual app (if all above conditions did not match)
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_read_timeout 35;
    proxy_send_timeout 35;

    proxy_pass http://api-app;
  }
}

そこで、CORSヘッダーセクションを次のように変更したいと思いました。

# ...
  set $cors '';

  if ($http_origin ~ '^https?://(some.domain|some.other.domain|other-allows.domain)') {
      set $cors 'true';
  }

  if ($cors = 'true') {
      more_set_headers 'Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE,OPTIONS';
      more_set_headers 'Access-Control-Allow-Origin: $http_origin';
      more_set_headers 'Access-Control-Allow-Credentials: true';
      more_set_headers 'Access-Control-Request-Method: GET,POST,PATCH,PUT,DELETE,OPTIONS';
      more_set_headers 'Access-Control-Request-Headers: Content-Type';
      more_set_headers 'Access-Control-Allow-Headers: Origin,X-Requested-With,Content-Type,Accept,Session-Id,Role-Id,Visitor-Id,X-Window-Location';
      more_set_headers 'Access-Control-Expose-Headers: X-Total-Entries,X-Total-Pages,X-Page,X-Per-Page,X-Folder-Hierarchy';
  }
  

  location / {
# ...

しかし、if ステートメントでは使用できないことがnginx -tすぐにわかりました。add_header も同様です。more_set_headers

私はそのセクションでそれがうまくいくだろうと考えましたlocation。しかし、私たち全員が知っているように、これは良い解決策ではないことはすでにわかっていましたnginx のロケーションセクションでは、そして、私は正しかったのです。すると、OPTIONS リクエストの CORS ヘッダーが失われることになりますが、私はすでに if ケース (返されるので OK です) を持っていました。

Nginxsを使用するオプションも見つかりましたマップ関数ただし、これはヘッダー値を変更する場合にのみ機能し、ヘッダーのブロック全体を追加する場合には機能しません。

私の質問は次のとおりです。 ヘッダーを条件付きで(マップを使用せずに)ロケーション ブロックの外側に追加する方法はありますか? 理想的には、CORS セクションのインクルードを許可して、複数のサーバー(つまり、nginx サイト)で使用できるようにします。

答え1

が空の文字列を受け入れるかどうかはわかりませんmore_set_headers。受け入れる場合は、複数のmapステートメントを定義できます。

map $http_origin $cors_methods {
    default "";
    ~^https?://(some.domain|some.other.domain|other-allows.domain) Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE,OPTIONS;
}

map $http_origin $cors_origin {
    default "";
    ~^https?://(some.domain|some.other.domain|other-allows.domain) Access-Control-Allow-Origin: $http_origin;
}

そしてこれを使います:

more_set_headers $cors_methods;
more_set_headers $cors_origin;

関連情報