支付服务配置指南

本文档介绍如何配置 Vibany 项目的支付系统,支持支付宝/微信支付(国内)和 Stripe(国际)。

支持的支付方式

支付方式提供商适用地区特点
支付宝易支付 (dulupay)中国大陆用户习惯,费率低
微信支付易支付 (dulupay)中国大陆移动优先
信用卡Stripe全球国际通用
Apple PayStripe全球苹果用户首选

易支付配置(支付宝/微信)

易支付是一个聚合支付平台,支持支付宝和微信支付。

1. 注册易支付账号

访问 https://s.zhaikr.com/epay 注册商户账号。

2. 获取 API 凭证

登录易支付后台:

  1. 进入 "用户中心" → "API 信息"
  2. 记录以下信息:
    • 商户 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

  1. 登录 Stripe Dashboard
  2. 进入 "Developers" → "API keys"
  3. 复制以下密钥:
    • Secret key(测试环境用 sk_test_,生产用 sk_live_

3. 配置 Webhook

Stripe 需要配置 Webhook 来接收支付结果通知:

3.1 创建 Webhook Endpoint

  1. 在 Dashboard → Developers → Webhooks
  2. 点击 "Add endpoint"
  3. 输入 Endpoint URL:
    https://yourdomain.com/api/public/stripe/notify
    
  4. 选择要监听的事件:
    • checkout.session.completed
    • checkout.session.async_payment_succeeded
    • payment_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

支付流程说明

支付宝/微信支付流程

  1. 创建订单:用户在前端选择充值金额
  2. 生成支付链接:后端调用易支付 API 创建订单,返回支付二维码 URL
  3. 用户支付:用户扫描二维码完成支付
  4. 异步通知:易支付发送回调通知到 /api/public/epay/notify
  5. 更新订单:系统验证签名后更新订单状态并充值积分
  6. 页面跳转:支付完成后跳转到结果页面

Stripe 支付流程

  1. 创建 Checkout Session:后端调用 Stripe API 创建支付会话
  2. 跳转到 Stripe:前端重定向到 Stripe Checkout 页面
  3. 用户支付:用户在 Stripe 页面输入信用卡信息完成支付
  4. 返回网站:支付完成后返回 /payment/success/payment/cancel
  5. Webhook 通知:Stripe 发送 checkout.session.completed 事件
  6. 更新订单:系统验证 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 验证失败

常见原因

  1. Webhook Secret 配置错误
  2. 请求体被修改(如 Nginx 重写)
  3. 使用了错误的签名密钥

解决方案

  1. 重新复制 Webhook Secret
  2. 确保 Nginx 不修改请求体
  3. 使用 stripe listen 本地测试

订单状态不同步

手动修复

在 Admin 后台可以手动查看和修复订单:

  1. 进入 /admin/orders
  2. 找到问题订单
  3. 查看支付平台状态
  4. 手动同步或退款

费用说明

易支付费用

支付方式费率结算周期
支付宝约 0.6%T+1
微信支付约 0.6%T+1

Stripe 费用

地区费率结算周期
中国大陆约 3.7% + ¥1.807 天
香港3.4% + HK$2.357 天
美国2.9% + $0.302 天
国际卡+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

相关文档

© copyright Justin 2025. All rights reserved.