⛏️
Next.jsでStripe決済を実装する時に起こしたミス
やりたいこと
Next.js App RouterとStripe Checkoutを連携し、以下の安全でスムーズな決済フローを実現したい
- ユーザーが決済ボタンをクリック
- サーバー側でStripe Checkoutセッションを作成
- 取得したCheckout URL(外部サイト)にリダイレクト
- ユーザーがStripe上で決済を完了
- 設定済みの
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への遷移には適していない。内部的に以下のような処理が行われる
- 指定URLを Next.js 管理下のページとみなして RSC(React Server Components)を取得しようとする
- 外部サイト(この場合Stripe)に対して fetch を行う
- StripeはCORSヘッダーを許可していないためプリフライトリクエストでエラー
- 最終的には通常のブラウザ遷移にフォールバックされるが、開発中にはエラーやちらつきが発生
解決策
外部サイト(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