name: payment description: 集成Stripe、PayPal和支付处理器。用于实现支付、计费或订阅。
支付集成
安全地集成支付处理器。
何时使用
- 支付网关集成
- 订阅计费
- 结账流程
- Webhook处理
- PCI合规
Stripe 集成
设置
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
// 创建支付意图
async function createPayment(amount, currency = "usd") {
const paymentIntent = await stripe.paymentIntents.create({
amount: amount * 100, // 美分
currency,
automatic_payment_methods: { enabled: true },
metadata: { order_id: "order_123" },
});
return {
clientSecret: paymentIntent.client_secret,
id: paymentIntent.id,
};
}
订阅
// 创建订阅
async function createSubscription(customerId, priceId) {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [{ price: priceId }],
payment_behavior: "default_incomplete",
expand: ["latest_invoice.payment_intent"],
});
return {
subscriptionId: subscription.id,
clientSecret: subscription.latest_invoice.payment_intent.client_secret,
};
}
// 取消订阅
async function cancelSubscription(subscriptionId) {
return await stripe.subscriptions.update(subscriptionId, {
cancel_at_period_end: true,
});
}
Webhooks
import { buffer } from "micro";
export async function handleWebhook(req, res) {
const sig = req.headers["stripe-signature"];
const body = await buffer(req);
let event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET,
);
} catch (err) {
return res.status(400).send(`Webhook 错误: ${err.message}`);
}
switch (event.type) {
case "payment_intent.succeeded":
await handlePaymentSuccess(event.data.object);
break;
case "payment_intent.payment_failed":
await handlePaymentFailure(event.data.object);
break;
case "customer.subscription.deleted":
await handleSubscriptionCanceled(event.data.object);
break;
}
res.json({ received: true });
}
数据库模式
CREATE TABLE payments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
stripe_payment_id VARCHAR(255) UNIQUE,
amount DECIMAL(10,2) NOT NULL,
currency VARCHAR(3) DEFAULT 'usd',
status VARCHAR(50) NOT NULL,
metadata JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE subscriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
stripe_subscription_id VARCHAR(255) UNIQUE,
stripe_customer_id VARCHAR(255),
plan VARCHAR(50) NOT NULL,
status VARCHAR(50) NOT NULL,
current_period_start TIMESTAMP,
current_period_end TIMESTAMP,
canceled_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_payments_user ON payments(user_id);
CREATE INDEX idx_subscriptions_user ON subscriptions(user_id);
安全清单
- [ ] 永不记录完整卡号
- [ ] 各处使用HTTPS
- [ ] 验证Webhook签名
- [ ] 实现幂等性密钥
- [ ] 仅存储必要数据
- [ ] 使用Stripe.js收集卡信息
- [ ] 优雅处理错误
示例
输入: “添加Stripe支付” 行动: 设置Stripe,创建支付意图端点,添加Webhook处理器
输入: “实现订阅” 行动: 创建订阅流程,处理生命周期Webhooks,添加取消功能