⛏️

Next.jsでStripe決済を実装する時に起こしたミス

に公開

やりたいこと

Next.js App RouterとStripe Checkoutを連携し、以下の安全でスムーズな決済フローを実現したい

  1. ユーザーが決済ボタンをクリック
  2. サーバー側でStripe Checkoutセッションを作成
  3. 取得したCheckout URL(外部サイト)にリダイレクト
  4. ユーザーがStripe上で決済を完了
  5. 設定済みの success_url に自動遷移してアプリに戻る

エラー内容

当初、router.push を使ってStripeのCheckout URLにリダイレクトしようとしたところ、以下のCORSエラーが発生

Access to fetch at 'https://checkout.stripe.com/c/pay/cs_test_...' 
from origin 'http://localhost:3000' 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.

Failed to fetch RSC payload for https://checkout.stripe.com/c/pay/cs_test_...
Falling back to browser navigation.

該当コード

const [state, formAction] = useActionState(async (prevState, formData: FormData) => {
  const result = await createStripeSession(prevState, formData);

  if (result.status === "error") {
    toast({
      title: "エラーが発生しました",
      description: result.error,
      variant: "destructive",
    });
  } else if (result.status === "success") {
    router.push(result.redirectUrl); // これが問題
  }
}, initialState);

原因

router.push は Next.js アプリ内部でのルーティング用であり、外部URLへの遷移には適していない。内部的に以下のような処理が行われる

  1. 指定URLを Next.js 管理下のページとみなして RSC(React Server Components)を取得しようとする
  2. 外部サイト(この場合Stripe)に対して fetch を行う
  3. StripeはCORSヘッダーを許可していないためプリフライトリクエストでエラー
  4. 最終的には通常のブラウザ遷移にフォールバックされるが、開発中にはエラーやちらつきが発生

解決策

外部サイト(Stripe)のURLへ遷移する場合は、window.location.href を使用する

const [state, formAction] = useActionState(async (prevState, formData: FormData) => {
  const result = await createStripeSession(prevState, formData);

  if (result.status === "error") {
    toast({
      title: "エラーが発生しました",
      description: result.error,
      variant: "destructive",
    });
  } else if (result.status === "success") {
    window.location.href = result.redirectUrl; // 外部URLへの遷移に最適
  }
}, initialState);

なぜ window.location.href が適切なのか

  • Next.js のルーティング機構をバイパスし、ブラウザが直接外部URLへ遷移
  • RSCや内部fetch処理が行われず、CORSエラーを回避
  • ブラウザ標準の挙動のため、表示のちらつきや遅延がない
  • ネットワークエラーやログの煩雑さを防止でき、UX・開発者体験の双方が向上

参考リンク

Discussion