APIサーバを立てるためのCORS設定決定版

  • 72
    いいね
  • 1
    コメント

タイトルは釣り、かつ、自分のための備忘録です。

マイクロサービスアーキテクチャでサービスを構築すると、APIサーバをサービスごとに立てるわけですが、
ブラウザ上のJSエンジンからAPIサーバを叩く時に避けて通れないのが、Same-Origin Policy(同一生成元ポリシー)によるCORS (Cross-Origin Resource Sharing)制限です。

これを回避するには、APIサーバ側でAccess-Control-*ヘッダを適切に返す必要がありますが、どう設定するべきかの情報が意外と少ないので(自分的)これが決定版! という設定を考えてみました。

結論

nginxの場合の設定例です。

server {
    listen       80;
    server_name  site.localhost;

    charset utf-8;
    root /var/www/app/public;

    location / {
        # preflightに対するレスポンス指定
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin '*';
            add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE';
            add_header Access-Control-Allow-Headers 'Origin, Authorization, Accept, Content-Type';
            add_header Access-Control-Max-Age 3600;

            add_header Content-Type 'text/plain charset=UTF-8';
            add_header Content-Length 0;

            return 204;
         }

        try_files $uri /index.php?$query_string;
    }

    location ~ \.php$ {
        # alwaysオプションを付けて、常にヘッダが出力されるようにする
        add_header Access-Control-Allow-Origin '*' always;

        fastcgi_pass   localhost:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

ブラウザ上のJSエンジンは、APIサーバ(別ドメイン)にリクエストを投げる前にOPTIONSメソッドによるアクセスを行います。
これはAccess-Control-*情報を問い合わせるためのpreflightと呼ばれるアクセスです。

if($request_method = 'OPTIONS'){ 〜 }は、このpreflightに対するレスポンスを定義しています。
(レスポンスボディは特に無いので、204: No Responseを返す。)

ヘッダ
Access-Control-Allow-Origin アクセスを許可するOriginのURL。"*"で指定なし。
Access-Control-Allow-Methods 使用可能なメソッド
Access-Control-Allow-Headers 使用可能なリクエストヘッダ
Access-Control-Max-Age preflightの結果をキャッシュしても良い時間(秒)

実際の本アクセスの場合もAccess-Control-Allow-Originヘッダが無いと、JSエンジンがレスポンスをブロックしてしまいますので指定が必要です。

ただし、nginxの場合デフォルトでは(200系、300系の)特定レスポンスコード以外の場合はヘッダの追加をスキップしてしまうので(参考)、400系のエラーを返す場合に対応できるようにalways指定が必要になります。