@yanceyguan

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Laravel プロジェクトにおける CORS(クロスオリジン)リクエストの問題

Cloud Run に Laravel プロジェクトをデプロイする際、CSS や JS などの静的ファイルの読み込みで CORS(クロスオリジン)エラーが発生していますてください。

発生している問題・エラー

image.png

自分で試したこと

ルートファイル web.php に CORS ヘッダーを手動で追加しました。

Route::get('/build/assets/{path}', function ($path) {
    $fullPath = public_path("build/assets/{$path}");

    if (!file_exists($fullPath)) {
        abort(404);
    }

    return Response::file($fullPath, [
        'Content-Type' => mime_content_type($fullPath),
        'Access-Control-Allow-Origin' => 'https://my-server-domin',
        'Access-Control-Allow-Methods' => 'GET, OPTIONS',
        'Access-Control-Allow-Headers' => 'Content-Type, Authorization',
    ]);
})->where('path', '.*');

さらに、OPTIONS プリフライトリクエストの処理も追加しました

Route::options('/build/assets/{file}', function () {
    return response('', 204)
        ->header('Access-Control-Allow-Origin', 'https://my-server-domin')
        ->header('Access-Control-Allow-Methods', 'GET, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
})->where('file', '.*');

Cloud Run の起動コマンドは以下のように設定しました

CMD ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8080"]

※ Laravel のバージョンは 12.12 を使用しています。

それにもかかわらず、CORS の問題は解決されませんでした:frowning2:。なぜでしょうか?
0 likes

2Answer

Fiddler などのキャプチャツールを使って要求・応答ヘッダを調べて、CORS に必要なものがちゃんと含まれているか調べてみてはいかがですか。うまくいくケースがあるなら、それとダメなケースを比較するとかでヒントが見つかるかもしれません。

ところで、なぜ「CSS や JS などの静的ファイル」なのですか? それらは普通 link タグや script タグを使って取得すると思いますが。どこか根本的にやり方が間違っているような気がします。


【追記】

参考に CORS に対応できてない場合のエラーメッセージ、Fiddler で見た要求・応答ヘッダー、加えてきちんと CORS 対応できた場合のFiddler で見た要求・応答ヘッダーを書いた記事を以下に紹介しておきます。

繰り返しますが、なぜ「CSS や JS などの静的ファイル」で CORS 対応が必要なのですか?

CORS 対応が必要なのは、クロスドメインの Web API に fetch などを使って要求を出し、JSON 形式の応答を受け取るというようなケースが多いのですが、その場合は「CSS や JS などの静的ファイル」は関係ないです。

普通の Web ページでは「CSS や JS などの静的ファイル」は link タグや script タグを使って取得しますが、その場合 CORS 対応は必要ないです。

何か考え違いがあるような気がします。CORS 云々の議論を始める前にそのあたりをクリアにした方が良さそうです。

1Like

LaravelプロジェクトでCloud RunにおけるCORS問題について、複数の原因と解決方法があります。まず根本的な問題を特定してから適切な解決策を提示します。

主な問題の原因

1. php artisan serve の使用(最大の問題)

# 現在の設定(問題あり)
CMD ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8080"]

問題点:

  • 開発用サーバーのため、本番環境に不適切
  • 静的ファイルが効率的に配信されない
  • CORSヘッダーが正しく処理されない場合がある
  • パフォーマンスが低い

解決方法1: Nginx + PHP-FPMの使用(推奨)

Dockerfileの改善

FROM php:8.2-fpm

# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \
    nginx \
    supervisor \
    && rm -rf /var/lib/apt/lists/*

# Laravelの依存関係
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# アプリケーションコピー
WORKDIR /var/www/html
COPY . .

# Composer install
RUN composer install --no-dev --optimize-autoloader

# 権限設定
RUN chown -R www-data:www-data /var/www/html \
    && chmod -R 755 /var/www/html/storage

# Nginx設定
COPY docker/nginx.conf /etc/nginx/sites-available/default
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 8080

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

Nginx設定ファイル (docker/nginx.conf)

server {
    listen 8080;
    server_name _;
    root /var/www/html/public;
    index index.php;

    # 静的ファイルのCORS設定
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        add_header Access-Control-Allow-Origin "https://your-domain.com" always;
        add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
        
        # プリフライトリクエストの処理
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin "https://your-domain.com";
            add_header Access-Control-Allow-Methods "GET, OPTIONS";
            add_header Access-Control-Allow-Headers "Content-Type, Authorization";
            add_header Content-Length 0;
            add_header Content-Type text/plain;
            return 204;
        }
        
        expires 1y;
        access_log off;
        try_files $uri =404;
    }

    # Laravel用の設定
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

Supervisor設定 (docker/supervisord.conf)

[supervisord]
nodaemon=true
user=root

[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true

[program:php-fpm]
command=php-fpm
autostart=true
autorestart=true

解決方法2: Cloud Storage + CDNでの静的ファイル配信(推奨)

Laravel設定の変更

// config/filesystems.php
'disks' => [
    'gcs' => [
        'driver' => 'gcs',
        'project_id' => env('GOOGLE_CLOUD_PROJECT_ID'),
        'key_file' => env('GOOGLE_CLOUD_KEY_FILE'),
        'bucket' => env('GOOGLE_CLOUD_STORAGE_BUCKET'),
        'path_prefix' => env('GOOGLE_CLOUD_STORAGE_PATH_PREFIX', ''),
        'storage_api_uri' => env('GOOGLE_CLOUD_STORAGE_API_URI', null),
    ],
],

// config/app.php
'asset_url' => env('ASSET_URL', 'https://storage.googleapis.com/your-bucket'),

ビルドプロセスでの静的ファイルアップロード

# ビルド時に静的ファイルをCloud Storageにアップロード
npm run build
gsutil -m rsync -r -d public/build gs://your-bucket/build

# Cloud RunにはLaravelアプリケーションのみデプロイ

Cloud Storage bucket CORS設定

[
  {
    "origin": ["https://your-domain.com"],
    "method": ["GET", "OPTIONS"],
    "responseHeader": ["Content-Type", "Content-Length"],
    "maxAgeSeconds": 3600
  }
]
# CORS設定を適用
gsutil cors set cors.json gs://your-bucket

解決方法3: Laravel CORS パッケージの適切な設定

Laravel Sanctumを使用している場合

// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

fruitcake/laravel-cors パッケージの設定

composer require fruitcake/laravel-cors
// config/cors.php
return [
    'paths' => ['api/*', 'sanctum/csrf-cookie', 'build/assets/*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['https://your-domain.com'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,
];

デバッグ方法

1. ブラウザでの確認

// ブラウザのコンソールで確認
fetch('https://your-api-domain.com/build/assets/app.css', {
    method: 'GET',
    mode: 'cors'
})
.then(response => console.log('Success:', response))
.catch(error => console.log('CORS Error:', error));

2. curlでのテスト

# プリフライトリクエストのテスト
curl -H "Origin: https://your-domain.com" \
     -H "Access-Control-Request-Method: GET" \
     -H "Access-Control-Request-Headers: Content-Type" \
     -X OPTIONS \
     https://your-api-domain.com/build/assets/app.css -v

# 実際のリクエストのテスト
curl -H "Origin: https://your-domain.com" \
     https://your-api-domain.com/build/assets/app.css -v

推奨される最終的なアーキテクチャ

Frontend (Vercel/Netlify)
    ↓ CORS Request
Laravel API (Cloud Run) ← 静的ファイルは含まない
    ↓
Static Assets (Cloud Storage + CDN)

最も効果的な解決策:

  1. Cloud Storage + CDN で静的ファイルを配信
  2. Nginx + PHP-FPM でLaravelアプリケーションを実行
  3. 適切なCORS設定 をWebサーバーレベルで実装

この構成により、パフォーマンス、セキュリティ、メンテナンス性が大幅に向上します。

1Like

Your answer might help someone💌