Skip to content

Stripe 支付集成指南

Stripe 是全球最流行的在线支付平台,支持信用卡、借记卡、Apple Pay、Google Pay 等多种支付方式。Stripe 以开发者友好著称,API 设计优雅、文档完善,是 SaaS 产品收款的首选。

为什么选择 Stripe#

特性说明
全球支付支持 135+ 种货币,195+ 个国家
多种支付方式信用卡、Apple Pay、SEPA 等
订阅管理内置订阅计费系统
开发者友好优秀的 SDK 和文档
安全合规PCI DSS Level 1 认证

注册与配置#

1. 注册 Stripe#

  1. 访问 stripe.com
  2. 创建账户(需要非大陆地区银行账户收款)
  3. 完成业务认证

2. 获取 API 密钥#

Dashboard → Developers → API keys

Publishable key: pk_test_xxx(客户端使用)
Secret key: sk_test_xxx(服务端使用)

注意:测试环境使用 test 密钥,生产环境使用 live 密钥。

3. 安装 SDK#

Terminal window
# Node.js
npm install stripe
# React 组件
npm install @stripe/stripe-js @stripe/react-stripe-js

Checkout 集成#

Checkout 是 Stripe 托管的支付页面,最快捷的集成方式。

服务端创建会话#

app/api/checkout/route.ts
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) {
const { priceId } = await req.json()
const session = await stripe.checkout.sessions.create({
mode: 'payment', // 或 'subscription'
payment_method_types: ['card'],
line_items: [
{
price: priceId,
quantity: 1,
},
],
success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_URL}/cancel`,
})
return Response.json({ url: session.url })
}

客户端跳转#

async function handleCheckout() {
const response = await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ priceId: 'price_xxx' }),
})
const { url } = await response.json()
window.location.href = url
}

支付成功页面#

app/success/page.tsx
import Stripe from 'stripe'
export default async function SuccessPage({ searchParams }) {
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
const session = await stripe.checkout.sessions.retrieve(
searchParams.session_id
)
return (
<div>
<h1>支付成功</h1>
<p>订单号{session.id}</p>
</div>
)
}

订阅支付#

创建产品和价格#

Dashboard → Products → Add product

或通过 API:

// 创建产品
const product = await stripe.products.create({
name: 'Pro Plan',
description: '专业版订阅',
})
// 创建价格
const price = await stripe.prices.create({
product: product.id,
unit_amount: 1999, // 分为单位,即 $19.99
currency: 'usd',
recurring: { interval: 'month' },
})

订阅 Checkout#

const session = await stripe.checkout.sessions.create({
mode: 'subscription',
line_items: [
{
price: 'price_xxx',
quantity: 1,
},
],
success_url: '...',
cancel_url: '...',
})

管理订阅#

// 获取订阅
const subscription = await stripe.subscriptions.retrieve('sub_xxx')
// 取消订阅
await stripe.subscriptions.cancel('sub_xxx')
// 更新订阅
await stripe.subscriptions.update('sub_xxx', {
items: [{ price: 'price_new' }],
})

Customer Portal#

让用户自助管理订阅:

const session = await stripe.billingPortal.sessions.create({
customer: 'cus_xxx',
return_url: `${process.env.NEXT_PUBLIC_URL}/account`,
})
// 跳转到 session.url

Webhook 处理#

Webhook 用于接收支付事件通知,实现业务逻辑。

配置 Webhook#

Dashboard → Developers → Webhooks → Add endpoint

Endpoint URL: https://your-domain.com/api/webhook
Events: checkout.session.completed, customer.subscription.updated, ...

处理事件#

app/api/webhook/route.ts
import Stripe from 'stripe'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
export async function POST(req: Request) {
const body = await req.text()
const sig = req.headers.get('stripe-signature')!
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
)
} catch (err) {
return new Response('Webhook Error', { status: 400 })
}
switch (event.type) {
case 'checkout.session.completed':
const session = event.data.object as Stripe.Checkout.Session
// 处理支付成功
await handlePaymentSuccess(session)
break
case 'customer.subscription.updated':
const subscription = event.data.object as Stripe.Subscription
// 处理订阅更新
await handleSubscriptionUpdate(subscription)
break
case 'customer.subscription.deleted':
// 处理订阅取消
break
}
return new Response('OK')
}

常用事件#

事件触发时机
checkout.session.completedCheckout 支付成功
invoice.paid发票支付成功
invoice.payment_failed支付失败
customer.subscription.created新建订阅
customer.subscription.updated订阅更新
customer.subscription.deleted订阅取消

嵌入式支付表单#

使用 Stripe Elements 在页面内嵌入支付表单。

设置 Elements#

components/CheckoutForm.tsx
'use client'
import { loadStripe } from '@stripe/stripe-js'
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js'
const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!)
function CheckoutForm() {
const stripe = useStripe()
const elements = useElements()
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
if (!stripe || !elements) return
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: `${window.location.origin}/success`,
},
})
if (error) {
console.error(error.message)
}
}
return (
<form onSubmit={handleSubmit}>
<PaymentElement />
<button type="submit" disabled={!stripe}>
支付
</button>
</form>
)
}
export default function Checkout({ clientSecret }: { clientSecret: string }) {
return (
<Elements stripe={stripePromise} options={{ clientSecret }}>
<CheckoutForm />
</Elements>
)
}

创建 PaymentIntent#

app/api/create-payment-intent/route.ts
export async function POST(req: Request) {
const { amount } = await req.json()
const paymentIntent = await stripe.paymentIntents.create({
amount,
currency: 'usd',
})
return Response.json({ clientSecret: paymentIntent.client_secret })
}

测试支付#

测试卡号#

卡号场景
4242 4242 4242 4242成功支付
4000 0000 0000 9995余额不足
4000 0000 0000 0002卡被拒绝

有效期:任意未来日期 CVC:任意 3 位数字

Stripe CLI#

Terminal window
# 安装
brew install stripe/stripe-cli/stripe
# 登录
stripe login
# 监听 Webhook(本地开发)
stripe listen --forward-to localhost:3000/api/webhook
# 触发测试事件
stripe trigger checkout.session.completed

最佳实践#

1. 使用幂等键#

防止重复扣款:

const paymentIntent = await stripe.paymentIntents.create(
{ amount: 1000, currency: 'usd' },
{ idempotencyKey: `order_${orderId}` }
)

2. 保存客户信息#

// 创建客户
const customer = await stripe.customers.create({
email: 'user@example.com',
metadata: { userId: 'user_123' },
})
// 关联到 Checkout
const session = await stripe.checkout.sessions.create({
customer: customer.id,
// ...
})

3. 处理 Webhook 签名#

始终验证 Webhook 签名,防止伪造请求。

4. 错误处理#

try {
const paymentIntent = await stripe.paymentIntents.create(...)
} catch (error) {
if (error instanceof Stripe.errors.StripeCardError) {
// 卡错误
} else if (error instanceof Stripe.errors.StripeInvalidRequestError) {
// 请求错误
}
}

常见问题#

国内能用 Stripe 吗?#

Stripe 不支持大陆主体直接注册。解决方案:

如何处理退款?#

const refund = await stripe.refunds.create({
payment_intent: 'pi_xxx',
amount: 1000, // 部分退款
})

多货币支持#

const session = await stripe.checkout.sessions.create({
currency: 'eur', // 欧元
// ...
})

参考资料#