Skip to content

Flutter WebでのCORSエラーの解決方法

問題の概要

Flutter Webアプリケーションを開発中、APIリクエストを行う際にCORS(Cross-Origin Resource Sharing)エラーが発生することがあります。この問題はモバイルアプリでは発生せず、Web版でのみ現れる特徴があります。

典型的なエラーメッセージ:

Access to XMLHttpRequest at 'https://api.example.com/endpoint' from origin 'http://localhost:52700' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

CORSとは

CORSはブラウザのセキュリティメカニズムで、異なるオリジン(ドメイン、プロトコル、ポート)間でのリソース共有を制御します。サーバーが適切なCORSヘッダーを返さない場合、ブラウザはセキュリティ上の理由でレスポンスをブロックします。

開発環境での一時的な解決策

重要

これらの方法は開発環境でのデバッグ用途のみに使用し、本番環境では絶対に使用しないでください。

方法1: ブラウザのセキュリティを無効化して実行

Flutter 3.3.0以降では、コマンドラインオプションで直接ブラウザのセキュリティ設定を変更できます:

bash
flutter run -d chrome --web-browser-flag="--disable-web-security"

テストを実行する場合:

bash
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d web-server --web-browser-flag="--disable-web-security"

方法2: Android Studioでの設定

  1. 実行設定を編集します
  2. 「Additional run args」に以下を追加します:
    --web-browser-flag="--disable-web-security"

方法3: flutter_corsパッケージの使用

bash
# パッケージのインストール
dart pub global activate flutter_cors

# CORS制限の無効化
fluttercors --disable

# 再度有効化する場合
fluttercors --enable

パスが通っていない場合、.zshrcまたは.bashrcに以下を追加します:

bash
export PATH="$PATH":"$HOME/.pub-cache/bin"

本番環境での正しい解決方法

本番環境では、サーバー側で適切なCORS設定を行うことが唯一の正しい解決策です。

サーバー側でのCORS設定例

javascript
const express = require('express');
const cors = require('cors');
const app = express();

// すべてのオリジンを許可
app.use(cors());

// または特定のオリジンのみ許可
app.use(cors({
  origin: 'https://yourdomain.com'
}));
php
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization');
header('Access-Control-Max-Age: 1728000');

// OPTIONSリクエストの処理
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    exit(0);
}
// 通常の処理
python
from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # すべてのオリジンを許可

# または特定のオリジンのみ許可
# CORS(app, origins=['https://yourdomain.com'])
nginx
server {
    location / {
        # OPTIONSプリフライトリクエストの処理
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
            add_header 'Access-Control-Max-Age' 1728000;
            return 204;
        }

        # CORSヘッダーの追加
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
    }
}

Dartコードでのリクエスト設定

サーバー側でCORSが適切に設定されていれば、Dartコードは通常通りで問題ありません:

dart
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<void> makeRequest() async {
  final response = await http.post(
    Uri.parse('https://api.example.com/endpoint'),
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer your_token',
    },
    body: json.encode({
      'key': 'value',
    }),
  );
  
  if (response.statusCode == 200) {
    print('Success: ${response.body}');
  } else {
    print('Error: ${response.statusCode}');
  }
}

その他の注意点

  1. プリフライトリクエスト: 複雑なリクエスト(特定のContent-Typeやカスタムヘッダーを含む)の場合、ブラウザはまずOPTIONSリクエスト(プリフライト)を送信します。サーバーはこのリクエストにも適切に応答する必要があります。

  2. Credentials付きリクエスト: クッキーや認証情報を含むリクエストを送信する場合、より厳格なCORS設定が必要です:

    dart
    // Dart側
    headers: {
      'Authorization': 'Bearer your_token',
      'Content-Type': 'application/json',
    },
    credentials: true, // 必要に応じて
    javascript
    // サーバー側
    app.use(cors({
      origin: 'https://yourdomain.com',
      credentials: true
    }));
  3. Webレンダラーの変更: 場合によってはwebレンダラーを変更することで問題が解決することがあります:

    bash
    flutter run -d chrome --web-renderer html

まとめ

CORSエラーを解決するには:

  1. 開発中は一時的な解決策(ブラウザのセキュリティ無効化)を使用
  2. 本番環境では必ずサーバー側で適切なCORS設定を実装
  3. クライアント側のみでCORSを完全に解決することは不可能

サーバー側の設定ができない場合(外部APIなど)、APIプロバイダーが提供する正式なCORSサポート方法を確認するか、バックエンドを経由したプロキシ処理を検討してください。