模板web-nextjs
支付宝支付
在 web-nextjs 中集成支付宝 PC 网页支付和 H5 手机网站支付,含沙箱调试、安全配置和常见问题。
支付宝支付
技术架构图
支付时序图
准备工作
步骤 1:注册支付宝商家账号
前往 支付宝商家中心 注册商家账号,完成实名认证。
步骤 2:创建应用
登录 支付宝开放平台 → 控制台 → 创建应用,选择「网页&移动应用」。
步骤 3:申请支付产品
在应用中申请以下产品(需上传营业执照等资质材料):
- 电脑网站支付 — PC 端网页支付
- 手机网站支付 — H5 手机端支付
步骤 4:配置应用公钥
- 下载 支付宝密钥生成工具
- 在本地生成 RSA2048 密钥对(推荐 PKCS8 格式)
- 将应用公钥(公钥字符串,不含 PEM header/footer)粘贴到开放平台配置
- 妥善保存应用私钥(
-----BEGIN RSA PRIVATE KEY-----格式,后续配置环境变量使用)
步骤 5:获取配置信息
在开放平台「我的应用」页面记录以下信息:
- 应用 ID(APPID):形如
2021xxxxxxxx - 应用私钥:步骤 4 生成的 RSA2048 私钥
- 支付宝公钥:在「查看支付宝公钥」页面获取(注意:是支付宝公钥,不是你自己生成的应用公钥)
步骤 6:配置回调 URL
在应用设置中配置回调地址:
- 开发阶段:使用内网穿透 URL(详见「开发环境调试」章节)
- 生产阶段:使用真实 HTTPS 域名
环境变量配置
在 .env.local 中添加:
ALIPAY_APP_ID=2021xxxxxxxx # 应用 ID,在开放平台「我的应用」获取
ALIPAY_PRIVATE_KEY=MIIEowIBAAK... # 应用私钥,RSA2048,PKCS1 格式,不含 PEM header
ALIPAY_PUBLIC_KEY=MIIBIjANBgk... # 支付宝公钥(不是应用公钥),在开放平台「查看」
ALIPAY_NOTIFY_URL=https://你的域名/api/payments/alipay/notify开发环境调试
沙箱环境
- 登录开放平台 → 进入「沙箱环境」
- 获取沙箱 APPID 和密钥(与正式密钥不同)
- 沙箱买家账号:在「沙箱账号」页签获取测试用账号(账号 + 登录密码 + 支付密码)
参考:支付宝沙箱环境文档
内网穿透配置
支付宝需要向本地发送异步通知,必须使用内网穿透工具:
- 推荐 natapp:
- 注册账号 → 购买免费隧道 → 下载客户端
- 配置
authtoken,启动隧道指向127.0.0.1:3000 - 获得公网域名如
abc.natapp.cc
- 将
https://abc.natapp.cc/api/payments/alipay/notify填入.env.local的ALIPAY_NOTIFY_URL
完整沙箱测试流程
- 启动 natapp +
pnpm dev - 访问
/pricing→ 选择支付宝 - 跳转到沙箱收银台
- 用沙箱买家账号登录并支付
- 在终端观察 notify 回调日志
- 检查数据库
payments表状态是否变为paid
生产环境配置
- 将
.env.local中的沙箱 APPID 和密钥替换为正式密钥 ALIPAY_NOTIFY_URL改为生产 HTTPS 域名(必须 HTTPS,IP 地址不支持)- 在开放平台将应用提交上线审核(需完善资质材料)
- 审核通过后即可正式使用
安全注意事项
- ⚠️ 私钥绝不泄露到客户端:
ALIPAY_PRIVATE_KEY仅在 Route Handler(服务端)使用,绝不能以NEXT_PUBLIC_开头或出现在前端代码中 - ⚠️ 回调验签必须执行:每次收到支付宝异步通知(notify)时,必须调用
verifyAlipayNotify(formData)验证签名,拒绝签名不通过的请求(直接返回 HTTP 400),不可跳过 - ⚠️ 幂等性处理:根据
out_trade_no查询数据库,若已是paid状态则直接返回'success',避免重复处理 - ⚠️ 金额精度:支付宝金额单位为「元」(字符串,最多 2 位小数),数据库存储建议使用整数「分」,转换时:
分 / 100格式化为'0.01' - ⚠️ HTTPS 强制:生产环境的 notify URL 必须是 HTTPS;同步回调(return URL)也建议 HTTPS
常见问题(FAQs)
Q: 本地开发时收不到支付宝回调?
→ 需要内网穿透工具(natapp/cpolar),将公网 URL 配置为 ALIPAY_NOTIFY_URL。
Q: 验签失败(ISV.INVALID-SIGNATURE)?
→ 检查是否使用了「支付宝公钥」(不是应用公钥),以及公钥格式是否正确(不含 PEM header)。
Q: 支付后页面没有跳转到 return URL?
→ return_url 必须是 HTTPS 才会触发同步回调。
Q: 沙箱可以正常支付,生产环境失败? → 检查是否替换为正式密钥,应用是否已通过审核上线。
Q: 出现 INVALID_PARAMETER 错误?
→ 检查 APPID 是否与密钥匹配,金额格式是否正确(字符串,非负数)。
Q: 回调接收到但数据库未更新?
→ 检查 Supabase SERVICE_ROLE_KEY 是否正确,RLS 策略是否允许 insert/update。