CORSポリシーに関するエラー

CORSポリシーに関するエラーに多々遭遇していたのですが、なんとなくで解決していたので深く理解することを目標にこの記事を書いています。

##  CORSとは？
CORS(Cross-Origin Resource Sharing)とは異なるオリジン間のリクエストを制御するためのブラウザ機能になります。オリジンとは、URLのプロトコル、ホスト、ポートの組み合わせで定義されます。

###### *異なるオリジンの例*
* `https://example.com` と `http://example.com` → **プロトコルが異なる**
* `https://example.com:8080` と` https://example.com` → **ポートが異なる**
* `https://example.com` と `https://api.example.com` → **ホストが異なる**

## CORSエラーが発生する理由
CORSエラーは、ブラウザが送信したリクエストがサーバー側で許可されていない場合に発生します。エラーが発生した場合は、以下のようなエラーが表示されます。

```bash
Access to XMLHttpRequest at 'https://api.example.com/data' from origin 'https://frontend.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

## CORSエラーを実際に引き起こしてみる
CORSエラーを実際に引き起こしてみたいと思います。
まず、サーバー側はNode.jsを使用して構築します。

#### ステップ1: expressのインストール
expressを使用してサーバーを作成していきます。
まず最初に、プロジェクトを初期化して、package.jsonファイルを作成します。その後、パッケージをインストールします。


```bash
npm init -y
```
```bash
npm install express
```

#### ステップ2: Nodeアプリケーションの作成
簡単なNodeアプリケーションを作成していきます。今回は**ポート番号3000**を使用します

```javascript:server.js
const express = require("express")
const app = express()
const port = 3000

app.listen(port, ()=>{
    console.log(`Server is running on port ${port}`)
})

app.get("/data", (req, res) => {
    res.json({ message: "Hello World!" });
});
```

コードが書けたらNodeサーバーを起動します。
起動すると、`Server is running on port 3000`と表示されます。

```bash
node server.js
```




#### ステップ3: クライアント側の作成
以下のHTMLファイルを用意し、ブラウザで開きます。
`<script>`タグ内では、`fetch`関数を使用してサーバー（`http://localhost:3000/data`）にリクエストを送信します。
```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">[title](url)
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CORS</title>
</head>
<body>
    <h1>Hello Wolrd</h1>
    <script>
        fetch("http://localhost:3000/data")
            .then(response => response.json())
            .then(data => console.log(data))
            .catch(error => console.error("CORS Error:", error));
    </script>
</body>
</html>
```

ブラウザでアクセスするとこのように表示されます。
![スクリーンショット 2024-11-26 215810.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935088/0259de4c-8fee-85e0-6343-fccc4a735e14.png)

#### ステップ4: 検証ツールのconsoleを確認する
ウェブページ上で右クリック → 「検証」をクリックします。そうすると、上部にいろんなタブが出てくるので、Consoleを選択します。Consoleを開くと、赤くCORSエラーが表示されています。

![スクリーンショット 2024-11-26 220216.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935088/7141d780-788b-d644-5911-33e68fa4f5d5.png)

今回は、ポートが異なっているので、CORSエラーが出ていました。
* http://localhost:5500: クライアント側で動作しているオリジン
* http://localhost:3000: サーバー側で動作しているオリジン

## CORSエラーを解消する
ここまででCORSエラーを実際に確認することができたので、その解消を行っていきます。

#### ステップ1: `cors`ライブラリのインストール

```bash
npm install cors
```
#### ステップ2: サーバーコードにCORSを適用
下記のコードでは、どのオリジンからのリクエストも許可するCORSポリシーを設定しています。
```javascript:server.js
const express = require("express")
const app = express()
const cors = require("cors"); // corsをインポート
const port = 3000

// CORSを適用
app.use(cors());

app.listen(port, ()=>{
    console.log(`Server is running on port ${port}`)
})

app.get("/data", (req, res) => {
    res.json({ message: "Hello World!" });
});
```

#### ステップ3: 特定のオリジンを許可する
今回は、`http://localhost:5500`からアクセスをしたいので、こちらのオリジンからのみアクセスを許可するように設定をします。

```javascript:server.js
app.use(cors({
    origin: "http://localhost:5500"
}));
```
設定ができたら再度サーバーを起動します。

```bash
node server.js
```

#### ステップ4: 動作の確認
設定ができたので実際にCORSエラーは解消できているのか確認していきます。
先ほどのHTMLファイルをブラウザで開き、検証ツールで確認すると下記のように表示されているかと思います。

![スクリーンショット 2024-11-26 221900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3935088/6d0d680a-8d81-1d5b-af3d-4b32994539da.png)

#### ステップ5: 特定のオプションを追加する場合(おまけ)
リクエストに応じてヘッダーやHTTPメソッドを設定するオプションがもあります。

```javascript:server.js
app.use(cors({
    origin: "http://localhost:5500", // 許可するオリジン
    methods: ["GET", "POST"], // 許可するHTTPメソッド
    allowedHeaders: ["Content-Type", "Authorization"], // 許可するヘッダー
    credentials: true // Cookieなどの認証情報を許可
}));
```

## おわりに
websocketサーバーをALBを使用して負荷分散を行ってるいるのですが、CORSエラーがでてなかなか解決できず。。。難しいですね！
最後までご覧いただきありがとうございました！