2022/04現在、ドキュメントではStripe Checkoutで決済ページにリダイレクトする際に、「Stripe.js SDKのredirectToCheckout
を利用しない」方法を紹介しています。
この記事では、redirectToCheckout
を利用しない方法への切り替えについて紹介します。
redirectToCheckout
を利用しない理由
2021/09より、ドキュメントで紹介している標準的な方法から、redirectToCheckout
は外れています。
これにはいくつかの理由がありますが、2022/4時点で最もインパクトの大きい違いは、「カスタムドメインが利用できないこと」です。
redirectToCheckout
を利用したリダイレクトでは、カスタムドメインの適用されていないCheckoutページにリダイレクトします。
redirectToCheckout
を利用しない方法: サーバー側編
ドキュメントで紹介している方法は、サーバー側でリダイレクトさせるものです。
const session = await stripe.checkout.sessions.create({
line_items: [
{
// Provide the exact Price ID (for example, pr_1234) of the product you want to sell
price: '{{PRICE_ID}}',
quantity: 1,
},
],
mode: 'payment',
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/cancel.html`,
automatic_tax: {enabled: true},
});
res.redirect(303, session.url);
サーバー側でリダイレクトさせることで、HTTPステータスコードでもリダイレクトを示すことができます。
ただし、この方法に切り替えるには、「JSONを受けるAPIを非同期で呼び出す」のではなく、「ページを遷移する」必要があります。
form
タグを利用して遷移する方法や、Next.jsなどでリダイレクト用ページを用意する方法などに切り替えましょう。
form
タグを利用して遷移する方法
formタグを利用する場合、ボタンの実装は以下のようなイメージです。
<form action="/api/checkout_session" method="POST">
<input type='hidden' name='price' value="price_xxx" />
<input type='hidden' name='quantity' value="1" />
<button type='submit'>注文する</button>
</form>
サーバー側では、リクエストBodyからinputに設定したデータを取得して利用します。
export default async function handler(req, res) {
if (req.method.toLocaleLowerCase() !== 'post') {
return res.status(405).end()
}
const { price, quantity } = req.body
const stripe = new Stripe(process.env.STRIPE_API_KEY, {
apiVersion: '2020-08-27',
maxNetworkRetries: 3,
})
const session = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{
price,
quantity,
}],
success_url: 'http://localhost:3000',
cancel_url: 'http://localhost:3000/'
})
return res.redirect(301, session.url)
}
この方法は、複数の商品情報など、送信すべきデータの量が増えた場合の実装が複雑になる可能性があることに注意しましょう。
もしデータの量が多い場合や可変する場合などでは、form以外の方法でリダイレクトさせることも検討しましょう。
Next.jsでリダイレクト用ページを用意する方法
Next.jsなど、サーバー側の処理も実装できるフレームワークでは、リダイレクト用のページを用意する方法もとれます。
この場合、注文する商品データをCookieやカート用のデーターベースサービスに保存するなどの方法が必要です。
import { parseCookies } from "nookies";
export async function getServerSideProps(context) {
const cookies = parseCookies(context)
const userId = typeof cookies.userId === "undefined" ? "" : cookies.userId
// 外部DBまたはCookieなどからカートのデータを受け取る
const cartItem = await getCartItemByUserId(userId)
try {
// セッションを作成する
const session = await stripe.checkout.sessions.create({ /*..*/ })
res.redirect(303, session.url);
if (!session || !session.url) {
throw new Error("Failed to create a new checkout session")
}
context.res.writeHead(303, {
Location: session.url
})
context.res.end()
} catch (e) {
return {
props: {
errorMessage: e.message
}
}
}
}
この方法では、pages/checkout_session.js
のように、Checkout Sessionを作成してリダイレクトする専用のページを用意しています。
成功した場合はリダイレクトされるので、ページのコンポーネントではエラー情報を表示させるか、こちらもTOPページなどにリダイレクトさせる方法などをとります。
redirectToCheckout
を利用しない方法: クライアント側編
もしサーバー側でリダイレクトを組み込むのが難しい場合は、クライアント側でredirectToCheckout
を利用しない実装を行います。
もっとも手早い方法は、window.open
やlocation.href
でリダイレクトまたは別窓でページを開くことです。
// Checkout Sessionの結果を受け取るAPI
const session = await fetch('/api/checkout_session').then(data => data.json())
- await stripe.redirectToCheckout({ sessionId: session.id })
+ window.open(session.url) // 別窓にする場合
+ location.href = session.url // 同じ窓で遷移する場合
この実装の場合、APIのレスポンスにsession
のid
ではなくurl
を含める必要があることに注意しましょう。
終わりに
redirectToCheckout
を使わずにCheckoutの決済ページに移動する方法を紹介しました。
APIが利用できなくなるわけではありませんが、ドメインのようにうまく動かない機能もあるため、利用にはご注意ください。