【Nuxt3】serverディレクトリで実装したAPIにCORS対策を行う

Nuxt3を使用したフロントエンド開発を行う中で、APIをNuxt3のserverディレクトリを使ってモックしていました。
しかし、ロードバランサーを経由する形でフロントエンドにアクセスをしたところ、そのAPIがCORSエラーになってしまいました。

この問題を解決する手順について対策中に出たいくつかのエラーをの解決策も含めて解説をします。

# 完成したコード

`server/middleware/cors.js`を作成し、以下のコードを記述します。

```javascript
// server/middleware/cors.js
export default defineEventHandler((event) => {
  const method = event.node.req.method

  // 許可するオリジン（=ロードバランサーのオリジン）
  const allowedOrigins = ['http://localhost:8133']
  const origin = event.node.req.headers.origin

  if (allowedOrigins.includes(origin)) {
    setHeader(event, 'Access-Control-Allow-Origin', origin)
  } else {
    setHeader(event, 'Access-Control-Allow-Origin', 'null')
  }

  setHeader(event, 'Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS')
  setHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization, payloadpath')
  setHeader(event, 'Access-Control-Allow-Credentials', 'true')

  if (method === 'OPTIONS') {
    setHeader(event, 'Access-Control-Max-Age', '86400') // 24 hours
    event.node.res.statusCode = 204 // No Content
    event.node.res.end()
    return
  }
})
```
### コードの説明
- allowedOriginsに許可するオリジンを定義します。ここでは、http://localhost:8133が許可されています
- リクエストのオリジンが許可されたオリジンに含まれている場合にAccess-Control-Allow-Originヘッダーを設定します
- すべてのHTTPメソッドを許可するためにAccess-Control-Allow-Methodsヘッダーを設定します
- 必要なヘッダーを許可するためにAccess-Control-Allow-Headersヘッダーを設定します
- 認証情報を含むリクエストを許可するためにAccess-Control-Allow-Credentialsヘッダーを設定します
- プリフライトリクエスト（OPTIONSメソッド）に対して、適切なレスポンスを返すように設定します


次に、`nuxt.config.js`でこのミドルウェアを適用します。

```javascript
const config = {    
    serverMiddleware: ["~/server/middleware/cors.js"],
};

export default defineNuxtConfig(config);
```

# 途中で出たエラーの説明と対策

### 1. 初めに発生したエラー

#### エラーメッセージ
```
Access to fetch at 'http://localhost:3000/api/sample' from origin 'http://localhost:8133' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
```

#### 原因
プリフライトリクエスト（OPTIONSメソッド）がリダイレクトされると、CORSのポリシーに違反します。

##### 対策
```javascript
if (method === 'OPTIONS') {
    setHeader(event, 'Access-Control-Max-Age', '86400') // 24 hours
    event.node.res.statusCode = 204 // No Content
    event.node.res.end()
    return  
}
```
プリフライトリクエストに対して適切なレスポンスを返すようにミドルウェアを設定しました。

### 2. 次に発生したエラー

#### エラーメッセージ
```
Access to fetch at 'http://localhost:3000/api/sample' from origin 'http://localhost:8133' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
```

#### 原因
リクエストが認証情報（クッキーや認証ヘッダー）を含んでいる場合、`Access-Control-Allow-Origin`ヘッダーにワイルドカード（`*`）を使用できません。

##### 対策
```javascript
// 許可するオリジン（=ロードバランサーのオリジン）
const allowedOrigins = ['http://localhost:8133']
const origin = event.node.req.headers.origin

if (allowedOrigins.includes(origin)) {
    setHeader(event, 'Access-Control-Allow-Origin', origin)
} else {
    setHeader(event, 'Access-Control-Allow-Origin', 'null')
}
```
特定のオリジン（`http://localhost:8133`）を許可するようにミドルウェアを設定しました。

### 3. 最後に発生したエラー

#### エラーメッセージ
```
Access to fetch at 'http://localhost:3000/api/sample' from origin 'http://localhost:8133' has been blocked by CORS policy: Request header field payloadpath is not allowed by Access-Control-Allow-Headers in preflight response.
```

#### 原因
リクエストヘッダー`payloadpath`が`Access-Control-Allow-Headers`に含まれていないため、CORSポリシーに違反しました。

#### 対策
```javascript
setHeader(event, 'Access-Control-Allow-Headers', 'Content-Type, Authorization, payloadpath')
```
`payloadpath`ヘッダーを許可するようにミドルウェアを設定しました。

# まとめ
CORSエラーの解消には、適切なCORSヘッダーを設定し、プリフライトリクエストを正しく処理することが重要です。

今回の例では、ロードバランサー経由でのアクセスに対して特定のオリジンを許可し、必要なヘッダーを設定するミドルウェアを作成することで問題を解決しました。

これにより、ローカル開発環境でのAPI呼び出しが正常に動作するようになりました。