支付服务配置指南
本文档介绍如何配置 Vibany 项目的支付系统,支持支付宝/微信支付(国内)和 Stripe(国际)。
支持的支付方式
| 支付方式 | 提供商 | 适用地区 | 特点 |
|---|---|---|---|
| 支付宝 | 易支付 (dulupay) | 中国大陆 | 用户习惯,费率低 |
| 微信支付 | 易支付 (dulupay) | 中国大陆 | 移动优先 |
| 信用卡 | Stripe | 全球 | 国际通用 |
| Apple Pay | Stripe | 全球 | 苹果用户首选 |
易支付配置(支付宝/微信)
易支付是一个聚合支付平台,支持支付宝和微信支付。
1. 注册易支付账号
访问 https://s.zhaikr.com/epay 注册商户账号。
2. 获取 API 凭证
登录易支付后台:
- 进入 "用户中心" → "API 信息"
- 记录以下信息:
- 商户 ID (PID)
- 平台公钥 (Public Key)
- 商户私钥 (Private Key)
3. 配置回调地址
在易支付后台设置支付回调 URL:
https://yourdomain.com/api/public/epay/notify
重要:
- 必须使用 HTTPS
- 域名需已备案(中国大陆服务器)
- 确保回调地址可以被外部访问
4. 配置环境变量
# 易支付 API 地址
PAY_API_URL=https://api.dulupay.com
# 商户 ID
PAY_PID=your_payment_id
# 平台公钥(从易支付后台获取)
PAY_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
# 商户私钥(从易支付后台获取)
PAY_MERCHANT_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
5. 启用/禁用支付方式
在 .env.local 中控制支付方式显示:
# 禁用微信支付
NEXT_PUBLIC_WXPAY_DISABLED=on
# 禁用支付宝
NEXT_PUBLIC_ALIPAY_DISABLED=on
# 同时禁用
NEXT_PUBLIC_WXPAY_DISABLED=on
NEXT_PUBLIC_ALIPAY_DISABLED=on
Stripe 配置(国际支付)
Stripe 支持信用卡、Apple Pay、Google Pay 等国际支付方式。
1. 注册 Stripe 账号
访问 https://stripe.com 注册账号。
2. 获取 API Keys
- 登录 Stripe Dashboard
- 进入 "Developers" → "API keys"
- 复制以下密钥:
- Secret key(测试环境用
sk_test_,生产用sk_live_)
- Secret key(测试环境用
3. 配置 Webhook
Stripe 需要配置 Webhook 来接收支付结果通知:
3.1 创建 Webhook Endpoint
- 在 Dashboard → Developers → Webhooks
- 点击 "Add endpoint"
- 输入 Endpoint URL:
https://yourdomain.com/api/public/stripe/notify - 选择要监听的事件:
checkout.session.completedcheckout.session.async_payment_succeededpayment_intent.succeeded
3.2 获取 Webhook Secret
创建 Webhook 后会显示 Signing secret(格式:whsec_...),记录下来。
4. 配置环境变量
# Stripe Secret Key
# 测试环境使用 sk_test_ 开头的密钥
# 生产环境使用 sk_live_ 开头的密钥
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key
# Stripe Webhook Signing Secret
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret
5. 本地测试 Webhook
使用 Stripe CLI 在本地测试 Webhook:
# 安装 Stripe CLI
brew install stripe/stripe-cli/stripe
# 登录
stripe login
# 转发 Webhook 到本地
stripe listen --forward-to localhost:3000/api/public/stripe/notify
运行后会显示 Webhook signing secret,用于本地测试。
6. 启用/禁用 Stripe
# 禁用 Stripe 支付
NEXT_PUBLIC_STRIPE_DISABLED=on
支付流程说明
支付宝/微信支付流程
- 创建订单:用户在前端选择充值金额
- 生成支付链接:后端调用易支付 API 创建订单,返回支付二维码 URL
- 用户支付:用户扫描二维码完成支付
- 异步通知:易支付发送回调通知到
/api/public/epay/notify - 更新订单:系统验证签名后更新订单状态并充值积分
- 页面跳转:支付完成后跳转到结果页面
Stripe 支付流程
- 创建 Checkout Session:后端调用 Stripe API 创建支付会话
- 跳转到 Stripe:前端重定向到 Stripe Checkout 页面
- 用户支付:用户在 Stripe 页面输入信用卡信息完成支付
- 返回网站:支付完成后返回
/payment/success或/payment/cancel - Webhook 通知:Stripe 发送
checkout.session.completed事件 - 更新订单:系统验证 Webhook 签名后更新订单并充值积分
订单和积分系统
订单状态
type OrderStatus = "PENDING" | "SUCCESS" | "FAILED" | "REFUND";
- PENDING:订单已创建,等待支付
- SUCCESS:支付成功,积分已充值
- FAILED:支付失败或超时
- REFUND:已退款
积分充值
支付成功后,系统会自动为用户充值积分:
// 充值积分函数
await rechargeUserPoints({
userId: order.userId,
points: order.amount,
description: `支付宝充值 - 订单${order.id}`,
metadata: { orderId: order.id, paymentMethod: 'alipay' }
});
交易记录
所有积分变动都记录在 wallets.extra.transactions 中:
interface Transaction {
id: string;
points: number; // 正数为充值,负数为消费
type: 'credit' | 'debit';
description: string;
createdAt: string;
}
故障排除
支付回调不触发
检查清单:
- 回调 URL 配置正确且使用 HTTPS
- 域名可访问,防火墙未拦截
- 服务器日志中能看到回调请求
- 签名验证通过
调试方法:
# 查看服务器日志
tail -f /var/log/nginx/access.log
tail -f ~/.pm2/logs/image-render-out.log
Stripe Webhook 验证失败
常见原因:
- Webhook Secret 配置错误
- 请求体被修改(如 Nginx 重写)
- 使用了错误的签名密钥
解决方案:
- 重新复制 Webhook Secret
- 确保 Nginx 不修改请求体
- 使用
stripe listen本地测试
订单状态不同步
手动修复:
在 Admin 后台可以手动查看和修复订单:
- 进入
/admin/orders - 找到问题订单
- 查看支付平台状态
- 手动同步或退款
费用说明
易支付费用
| 支付方式 | 费率 | 结算周期 |
|---|---|---|
| 支付宝 | 约 0.6% | T+1 |
| 微信支付 | 约 0.6% | T+1 |
Stripe 费用
| 地区 | 费率 | 结算周期 |
|---|---|---|
| 中国大陆 | 约 3.7% + ¥1.80 | 7 天 |
| 香港 | 3.4% + HK$2.35 | 7 天 |
| 美国 | 2.9% + $0.30 | 2 天 |
| 国际卡 | +1% | - |
安全注意事项
1. 密钥保护
- 不要将支付私钥提交到 Git
- 生产环境使用 Live 密钥
- 定期轮换密钥
2. 签名验证
所有支付回调都必须验证签名:
// 易支付签名验证
const isValid = verifyRSASignature(params);
if (!isValid) {
return new Response('Invalid signature', { status: 400 });
}
// Stripe 签名验证
const event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!
);
3. 幂等性处理
防止重复处理同一笔支付:
// 检查订单是否已处理
if (order.status === 'SUCCESS') {
return new Response('Order already processed', { status: 200 });
}
测试支付
易支付测试
使用小额金额(如 0.01 元)进行测试。
Stripe 测试
使用 Stripe 提供的测试卡号:
| 卡号 | 场景 |
|---|---|
| 4242 4242 4242 4242 | 支付成功 |
| 4000 0000 0000 0002 | 卡片被拒绝 |
| 4000 0000 0000 9995 | 余额不足 |
更多测试卡号:Stripe Testing Documentation