RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-05-11中級

「CORSエラー」と表示されたとき、実は別の問題が隠れている — Rork + Supabase Edge Functions

RorkアプリでSupabase Edge FunctionsをAPIとして使うとCORSエラーが出る問題を解説。React Nativeの仕組み上、実は本当のCORSエラーは起きにくく、別の根本原因が隠れていることがほとんどです。

Supabase33Edge Functions2CORS2トラブルシューティング77React Native209

Supabase Edge Functions を呼び出したら Access-Control-Allow-Origin エラーが出た、という相談を受けるたびに、実際のエラーログを確認すると「これは CORS の問題ではなかった」というケースに何度も遭遇してきました。

2014年からアプリ開発を続けてきた経験でいうと、「CORS エラー」という表現はかなり広い意味で使われていて、ネットワーク越しの API 呼び出しで何かがうまくいかないと、すべて CORS のせいにされてしまうことがあります。Rork + Supabase の組み合わせでも、同じ構造のすれ違いが起きやすいです。

React Native アプリでは、本来 CORS は発動しない

まず前提として確認しておきたいのが、CORS(Cross-Origin Resource Sharing)はブラウザのセキュリティ機能だということです。

ブラウザは https://example.com で動くページから https://api.another.com に fetch を投げると、オリジンが違うとして CORS のチェックを行います。これは「ユーザーが知らないうちに別サービスに情報を送りつけられる」攻撃を防ぐための仕組みです。

React Native(Rork のベースとなっているフレームワーク)のアプリは、iOS や Android のネイティブランタイム上で動いています。ブラウザではありません。そのため、スマートフォンアプリとして実機や TestFlight 上で動かしている限り、CORS の制約は原理上かかりません。

// React Native では以下の fetch に CORS 制約はかからない
const { data, error } = await supabase.functions.invoke('my-function', {
  body: { message: 'hello' }
})

では、なぜ「CORS エラー」のような症状が出るのでしょうか。以下の 3 パターンで原因を整理してみます。

パターン1 — Rork Companion(ブラウザプレビュー)でテストしているケース

Rork の開発中に PC ブラウザ上の Companion でプレビューすると、そのプレビューはブラウザ環境で動作します。この場合に限っては、本物の CORS 制約が発動します。

スマートフォンの実機ではまったく問題なかったのに、ブラウザプレビューだけでエラーになる場合は、Edge Function 側に CORS ヘッダーを追加するだけで解消します。

// supabase/functions/my-function/index.ts
 
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers':
    'authorization, x-client-info, apikey, content-type',
}
 
Deno.serve(async (req) => {
  // OPTIONS(プリフライトリクエスト)への応答
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }
 
  try {
    const { message } = await req.json()
    const result = { response: `Received: ${message}` }
 
    return new Response(JSON.stringify(result), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    })
  } catch (error) {
    // エラーレスポンスにも必ず corsHeaders を付ける
    return new Response(JSON.stringify({ error: error.message }), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      status: 400,
    })
  }
})

ポイントは 2 つです。OPTIONS リクエスト(プリフライト)への応答と、エラーレスポンスを含むすべてのレスポンスcorsHeaders を付けること。エラーレスポンスに CORS ヘッダーが付いていないと、ブラウザはエラーの内容を読めずに CORS エラーとして表示してしまいます。

パターン2 — Edge Function が 500 エラーでクラッシュしているケース

実機での動作確認中に CORS 的な症状が出る場合、Edge Function 自体がエラーで落ちていることがほとんどです。これが最も見落とされやすいケースです。

Supabase の Edge Function が未ハンドルの例外でクラッシュすると、Deno ランタイムはデフォルトのエラーレスポンスを返しますが、このとき CORS ヘッダーが付いていないことがあります。ブラウザプレビューで見ると「CORS エラー」として表示されるため、CORS の問題と誤認されます。

診断手順は以下の通りです:

  1. Supabase ダッシュボードの「Edge Functions」→「Logs」を開く
  2. 呼び出したタイミングのログを確認する
  3. ErrorUncaught が含まれていれば、CORS ではなく Edge Function 自体のバグ
// よくある失敗パターン: try-catch を忘れている
Deno.serve(async (req) => {
  const { userId } = await req.json()  // ← ここで例外が起きるとクラッシュ
  const user = await getUser(userId)    // ← DB エラーでもクラッシュ
  return new Response(JSON.stringify(user))
})
 
// 修正版: try-catch で必ず捕捉し、エラーにも corsHeaders を付ける
Deno.serve(async (req) => {
  const corsHeaders = { 'Access-Control-Allow-Origin': '*' }
 
  if (req.method === 'OPTIONS') {
    return new Response('ok', { headers: corsHeaders })
  }
 
  try {
    const body = await req.json()
    if (!body.userId) throw new Error('userId is required')
    const user = await getUser(body.userId)
    return new Response(JSON.stringify(user), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
    })
  } catch (error) {
    console.error('Function error:', error.message)
    return new Response(JSON.stringify({ error: error.message }), {
      headers: { ...corsHeaders, 'Content-Type': 'application/json' },
      status: 400,
    })
  }
})

パターン3 — 認証ヘッダーの設定ミスで 401 になっているケース

Supabase の supabase.functions.invoke() を使わず、生の fetch で Edge Function を呼び出している場合、Authorization ヘッダーが正しく設定されていないと 401 エラーになります。この 401 エラーが CORS ヘッダーなしで返ってくると、ブラウザプレビューでは CORS エラーのように見えます。

// ❌ 問題: Authorization ヘッダーが未設定
const response = await fetch(
  'https://xxxxx.supabase.co/functions/v1/my-function',
  {
    method: 'POST',
    body: JSON.stringify({ message: 'hello' }),
  }
)
 
// ✅ supabase-js のクライアントを使うと自動的にヘッダーが付く
const { data, error } = await supabase.functions.invoke('my-function', {
  body: { message: 'hello' },
})

supabase.functions.invoke() を使うと、プロジェクトの ANON_KEY と Authorization ヘッダーが自動で付与されます。生の fetch を使う場合は、以下のヘッダーが必要です:

const ANON_KEY = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY
 
const response = await fetch(
  'https://xxxxx.supabase.co/functions/v1/my-function',
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${ANON_KEY}`,
      'apikey': ANON_KEY,
    },
    body: JSON.stringify({ message: 'hello' }),
  }
)

CORS エラーに見える症状の診断フロー

3 つのパターンをまとめると、以下の順序で確認するとほとんどのケースで原因を特定できます。

ステップ 1: 実機(または iOS シミュレーター)でも同じエラーが出るか確認する

  • 実機で出ない → Rork Companion(ブラウザ)固有の問題 → Edge Function に CORS ヘッダーを追加
  • 実機でも出る → CORS の問題ではない、次へ

ステップ 2: Supabase ダッシュボードのログを確認する

  • Edge Function のエラーログがある → 関数自体のバグを修正(try-catch の追加)
  • ログが何も出ていない → 関数が呼び出されていない(URL か認証の問題)

ステップ 3: supabase.functions.invoke() を使っているか確認する

  • 生の fetch を使っている → supabase.functions.invoke() に変更するか、必要なヘッダーを手動で付ける

Supabase の Edge Functions は仕組みとしては非常に素直で、ログを丁寧に読むとほぼ必ず原因が見つかります。「CORS エラー」と表示されても、すぐに CORS の設定を変えるのではなく、まず実機テストとログ確認から始めると、遠回りせずに解決できます。

Supabase Edge Functions の詳細な設計パターンについては、Rork Max × Supabase Edge Functions & Row Level Security — セキュアな API 設計完全ガイドも合わせてご覧ください。データが取得できないといった別の Supabase トラブルについては、Rork アプリで Supabase のデータが取得できない・表示されないときの原因別対処法が参考になります。

同じ問題で詰まっている方の参考になれば幸いです。

シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-07-08
SVGアイコンがExpo Goでは出るのにビルドで消える — Rork製アプリでSVGを確実に表示する
Rork や Expo のアプリで .svg ファイルを import してもアイコンが表示されない、色が反映されないという問題を、metro.config.js と react-native-svg-transformer の設定、currentColor によるテーマ追従まで実際のコードで解決します。
開発ツール2026-06-23
ゲーミフィケーションでDAUは増えたのに継続率が動かなかった — Rork運用で効いた設計の立て直し
ポイント・バッジ・リーダーボードを入れるとDAUは上がりますが、継続率は別物です。サーバー権威のポイント台帳、燃え尽きないストリーク、新規を萎えさせないリーグ設計まで、Rork運用で効いた立て直しを実装コード付きで整理します。
開発ツール2026-06-12
Rork 製アプリの『書類とデータ』が数 GB に膨らむときの原因と対処 — expo-image のディスクキャッシュ管理
アプリ本体は小さいのに『書類とデータ』だけが数 GB に膨らむ——壁紙アプリの運用で実際に踏んだ expo-image のディスクキャッシュ肥大を、cachePolicy の使い分け・縮小版配信・世代別クリアの三段構えで解決した記録です。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →