概要
Cloud Run上でバックエンドAPIを運用していると、フロントエンド(Vercelやローカル開発環境)からのリクエスト時にCORSエラーが発生することがあります。この記事ではCORSエラーをCloud Run環境下で解消した方法を解説します。
CORSとは
簡単にいうとブラウザが仲介者としてクライアントとサーバーの間で安全確認をする仕組み のことです。
CORSエラーとは何か
たとえば自分のWebアプリがhttp://localhost:3000で動いていて、
そこから別のサイトにデータを取りに行くとします。
このとき「そのAPIは本当に安全かわからないので、勝手にアクセスしてはダメかもしれない」と安全性の観点でブラウザに止められることがCORSエラーです。
CORSエラーの具体例
ブラウザがフロントからサーバーにリクエストを送信しようとしたとき、
次のようなエラーが出ました。
- フロント:
https://xxxx.vercel.app - サーバー:
https://xxxx-server-xxxxxx.run.app
Access to fetch at 'https://rootlink-server.run.app/chat' from origin 'https://rootlink.vercel.app' has been blocked by CORS policy.
原因
ブラウザはセキュリティのため、本リクエストを送る前に下見をします。これが「プリフライトリクエスト(OPTIONS)」です。
- ブラウザがまず OPTIONS をサーバーに送信
- サーバーがこのサイト安全性をチェックする
- その後に本リクエスト(POSTなど)を送信
しかしサーバーが正しく返さないと、ブラウザは通信を止めます。
この場合、ブラウザはリクエストを送る前に プリフライトリクエストを自動で送信します。サーバーがこのプリフライトに正しく応答しないと、ブラウザが本リクエストをブロックしこのようなエラーが発生してしまいます。
解決策:Hono + Cloud Run の場合
Cloud RunでHonoを使っている場合、以下のようにCORSをグローバルに設定することで解消できます。
// --- 必要なモジュールを読み込み ---
// Hono: 軽量なWebサーバーフレームワーク(Expressの代わり)
import { Hono } from 'hono';
// CORS(他のサイトからのアクセス制限)を設定するためのミドルウェア
import { cors } from 'hono/cors';
// Node.jsでHonoアプリを動かすための関数
import { serve } from '@hono/node-server';
// --- アプリ本体を作成 ---
const app = new Hono();
// --- CORS設定 ---
// どのサイト(オリジン)からアクセスを許可するかを定義
app.use(
'/*', // すべてのルートに適用
cors({
// アクセス元(Origin)をチェック
origin: (origin) => {
// originが無い場合(例:サーバー内部の通信など)は全部許可
if (!origin) return '*';
// vercel.appドメイン(開発・本番)を許可
if (origin.endsWith('.vercel.app')) return origin;
// ローカル開発環境(Viteなど)を許可
if (origin === 'http://localhost:5173') return origin;
// 明示的に本番ドメインを許可
if (origin === 'https://rootlink.vercel.app') return origin;
// それ以外は一時的に全許可(※本番ではできるだけ制限する)
return '*';
},
// 許可するHTTPメソッド(GET, POSTなど)
allowMethods: ['GET', 'POST', 'OPTIONS'],
// 許可するヘッダー(Content-Typeなど)
allowHeaders: ['Content-Type', 'Authorization'],
})
);
// --- プリフライトリクエスト(OPTIONS)の明示的な処理 ---
// ブラウザが安全確認のために送るOPTIONSリクエストに対して、
// OKと返す ステータスコード204=成功
app.options('*', (c) => c.text('ok', 204));
// --- 通常のGETリクエスト(動作確認用) ---
// 例: https://rootlink-server-xxxxxx.run.app/ にアクセスしたら "OK" を返す
app.get('/', (c) => c.text('OK'));
// --- サーバーを起動 ---
// PORT環境変数があれば使い、なければ8080番で起動
const port = Number(process.env.PORT) || 8080;
// Honoアプリをサーバーとして起動
serve({ fetch: app.fetch, port });
まとめ
- CORSエラーはブラウザのセキュリティ機構によるもの
- サーバー側で
Access-Control-Allow-Origin等のヘッダーを正しく返す必要がある - Cloud Run上でHonoを使用する場合、
hono/corsを適用し、OPTIONSメソッドを処理すれば解消可能