永遠にlocalhostがCORSから弾かれた話

# 永遠にlocalhostがCORSから弾かれた話

ローカルで動作するフロントエンドアプリケーション（`http://localhost:3000`）から、別のドメインにあるAPIサーバーにリクエストを送ろうとしていました。しかし、ブラウザのコンソールには以下のようなエラーメッセージが表示され、リクエストが拒否されました。

```text
Access to fetch at 'https://example.com/api/users/create' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:3000, *', but only one is allowed.
```

一見すると、`Access-Control-Allow-Origin`ヘッダーに`http://localhost:3000`と`*`が同時に設定されていることが問題のように見えます。しかし、なぜこのような状況が発生しているのかを理解するために、原因を探ることにしました。

#### **原因を探る：CORS設定の競合**

まず、サーバー側の設定を確認しました。以下が実際に使用していたApacheの設定例です。

```apache
<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /path/to/your/app

    # HTTPをHTTPSにリダイレクト
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /path/to/your/app

    # SSL設定
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # CORSヘッダーの追加
    <IfModule mod_headers.c>
        Header always set Access-Control-Allow-Origin "*"
        Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, PATCH"
        Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
        Header always set Access-Control-Allow-Credentials "true"
    </IfModule>

    <Directory /path/to/your/app>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    # アプリケーションへのプロキシ設定
    ProxyPass /api http://localhost:3001/
    ProxyPassReverse /api http://localhost:3001/

    # Preflightリクエストを処理
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{REQUEST_METHOD} OPTIONS
        RewriteRule ^(.*)$ $1 [R=200,L]
    </IfModule>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

この設定ファイルでは、`Access-Control-Allow-Origin`ヘッダーを設定するために、Apacheの`mod_headers`モジュールを使用していました。この設定により、`*`として全てのオリジンからのリクエストを許可するようにしていたのですが、エラーメッセージによると、`http://localhost:3000`もヘッダーに含まれていることが問題でした。

この時点で、アプリケーション側でもCORSの設定が行われている可能性が頭をよぎりました。もしアプリケーション側でCORSの設定がされていると、Apacheの設定と競合し、結果としてヘッダーが重複して設定される可能性があります。この仮説をもとに、アプリケーションのCORS設定を再確認することにしました。

#### **問題解決：アプリケーションのCORS設定を無効化する**

アプリケーションの設定ファイルを調査したところ、CORSに関連する設定がいくつか見つかりました。具体的には、`rack-cors`や類似のミドルウェアが使用されており、これが原因でApacheの設定と競合していたようです。

次に行ったのは、これらの設定の削除です。設定ファイルからCORSに関連する設定をすべて削除し、その後、アプリケーションサーバーを再起動しました。

```bash
# サーバー再起動
rails s
```

サーバー再起動後、再度リクエストを試みると、今度はエラーが発生せず、期待通りにリクエストが成功しました。ApacheのCORS設定が正しく反映され、アプリケーション側の設定との競合が解消されたことを確認しました。

#### **学び：CORS設定の複数レイヤーに注意**

今回の経験を通じて学んだのは、CORS設定が複数のレイヤーで競合すると、予期しないエラーが発生する可能性があるということです。特に、フロントエンドとバックエンドが異なるドメインで動作している場合、CORS設定がどのように影響するかを慎重に管理する必要があります。

同じようなCORSエラーに遭遇した場合、まずはCORS設定が複数の場所で重複していないかを確認することが重要です。不要な設定は取り除き、シンプルな構成にすることで、こうした問題を未然に防ぐことができます。