九、saas-starter 本地支付验收
第 8 章已经把 web-pay 的收银台、支付网关、运营平台和运营 API 部署到了线上。本章不再启动本机的 web-pay 服务,而是只在本机启动 saas-starter,让它直接调用第 8 章上线后的 web-pay,完成最后一笔真实支付验收。
重要
🎯 本章目标: 用本地 saas-starter 跑通基于线上 web-pay 的完整支付流程。用户从本地 H5 创建订单后,进入线上收银台,选择支付宝或微信扫码支付;支付成功后,线上 web-pay 记录订单并通知本机 SaaS 后端更新业务订单和订阅状态。
做到这里,本教程基础主线就是 100%。 你已经证明自己的 SaaS 可以接入线上统一收银台和运营平台完成收款。之后可以按第 8 章同一套 OBS/CDN、宝塔后端和 CodeArts 流程上线 saas-starter 或继续开发自己的 SaaS 服务,不需要再单独完成一个新章节。
9.1 启动前确认
开始前先确认这些准备项已经完成:

重要
✅ 本章是真实支付验收,不是只看页面能不能打开。 如果支付宝 / 微信官方资料、支付参数或支付通道还没配好,可以先回到第 6 章补齐;否则本章只能验证 SaaS 能创建订单,无法完成真实付款和回调。
第 6 章已经在 web-pay 运营平台创建商户和应用,并把同一组
mchNo、appId、AppSecret写入saas-starter。支付宝或微信支付参数已经在运营平台保存并启用。
至少一个支付通道已经启用;本章建议优先验证
ALI_QR和WX_NATIVE。第 7 章已经证明
saas-starter后端、H5 前端和业务库本地可用。第 8 章的线上 web-pay 已经可访问:
pay.example.com、pay-api.example.com、paymanager.example.com、paymanager-api.example.com都已通过 HTTPS 验收。
再检查 saas-starter 本地后端配置:
zhcpay:
api-base-url: "https://pay-api.example.com"
cashier-base-url: "https://pay.example.com"
site-base-url: "http://localhost:5173"
小技巧
📌 这三个地址的方向不要混:api-base-url 调线上支付网关,cashier-base-url 跳线上收银台,site-base-url 仍然指向本机 SaaS H5。SaaS 通知地址不用手填,后端启动脚本会用本次 cloudflared 地址临时覆盖。
警告
⚠️ 本章本地只启动 saas-starter。api-base-url 和 cashier-base-url 必须指向第 8 章上线后的 web-pay 域名,不能再指向本机 localhost。
9.2 本地服务启动顺序
按下面顺序启动:

重要
🚀 本章只启动 SaaS 本地服务。 web-pay 的收银台、支付网关、运营平台和运营 API 都使用第 8 章的线上环境;不要再同时启动仓库根目录的 web-pay 本地脚本。
启动本机 Redis 和 ActiveMQ。
启动 SaaS 后端:
cd saas-starter
./env-scripts/start-local-test-backend.sh
脚本会构建并启动本地 SaaS 后端,默认监听:
http://localhost:9220
脚本还会生成 SaaS 的 cloudflared 公网通知地址,并写入:
saas-starter/logs/application-local-tunnel.yml
这个文件里的 zhcpay.notify-url 会覆盖本次运行配置。线上 web-pay 支付成功后,会通过这个公网地址通知本机 SaaS 后端:
https://xxxx.trycloudflare.com/api/pay/notify
小技巧
🔗 每次重启 SaaS 后端脚本,cloudflared 地址都可能变化。测试付款时以本次 application-local-tunnel.yml 生成的地址为准,不要继续使用旧地址。
警告
⚠️ 线上 web-pay 要能访问这个 SaaS tunnel。若 tunnel 进程断开、地址过期,或 application-local-tunnel.yml 不是本次启动生成的,支付成功后 web-pay 可能已经入账,但 SaaS 业务订单不会更新。
用 HBuilderX 启动 SaaS H5 前端:
打开 HBuilderX。
选择
文件->打开目录,打开saas-starter/frontend。选择
运行->运行到浏览器->Chrome或你常用的浏览器。以 HBuilderX 控制台输出的地址为准,默认通常是:
http://localhost:5173
重要
🎯 本章不需要运行仓库根目录的 ./env-scripts/start-local-test-backend.sh 或 ./env-scripts/start-local-test-frontend.sh。web-pay 已经在第 8 章上线,本章只用线上收银台、线上支付网关和线上运营平台。
小技巧
💡 如果 SaaS H5 仍然请求旧接口,先在 HBuilderX 里停止运行并重新运行到浏览器;必要时清理浏览器缓存或用无痕窗口复测。
9.3 创建一笔 SaaS 订单
打开 HBuilderX 输出的 SaaS H5 地址,通常是:
http://localhost:5173

进入订阅、续费或开通专业版页面,选择一个套餐并点击支付。预期结果:
重要
📌 每次改配置后都重新创建一笔新订单。 旧订单里可能已经固化了旧金额、旧通道或旧支付链接,不适合拿来验证刚改过的配置。
SaaS 后端生成业务订单。
SaaS 后端调用线上 web-pay 支付网关创建支付订单。
页面返回或跳转到线上收银台支付链接。
收银台地址指向第 8 章配置好的线上域名。
支付链接应该类似:
https://pay.example.com/#/hub/{zhcpayToken}
如果订单停在 SaaS 侧,先看 SaaS 后端日志:
saas-starter/logs/backend.local.log
重点确认:
mchNo、appId、AppSecret来自同一个 web-pay 应用。zhcpay.api-base-url指向线上pay-api域名。zhcpay.cashier-base-url指向线上收银台域名。SaaS 业务库中能写入订单记录。
警告
⚠️ 如果这里报签名失败、应用不存在、商户不存在或无可用通道,优先回到第 6 章核对同一组 mchNo、appId、AppSecret 和支付通道,不要先改前端页面。
9.4 进入线上收银台
订单创建成功后,浏览器会进入线上收银台:
https://pay.example.com/#/hub/{zhcpayToken}
预期结果:
收银台能展示订单金额。
收银台能展示支付宝和微信等可用支付方式。
选择支付宝时可以看到支付宝扫码或跳转支付页面。
选择微信时可以看到微信扫码支付页面。
线上运营平台订单页能看到这笔支付订单。




备注
📌 无 token 直接访问 https://pay.example.com 出现空白、错误页或缺少订单信息是预期行为。收银台需要 SaaS 创建订单后生成的 zhcpayToken 才能展示付款页。
小技巧
✅ 线上运营平台能看到这笔订单,说明 SaaS 已成功调用线上支付网关创建 web-pay 订单。此时如果收银台页面异常,排查重点从 SaaS 后端转到收银台前端、支付通道和线上 pay-api。
如果收银台没有支付方式,回到第 6 章检查支付参数和支付通道是否启用;如果线上页面仍是旧版本,回到第 8 章检查 OBS 上传和 CDN 刷新。
9.5 完成付款并验证回调
使用支付宝或微信完成扫码支付。第一笔建议用小金额验证,确认链路稳定后再继续扩展业务场景。
危险
🔐 第一笔用真实小额支付。 本章已经进入真实支付链路,不要用大金额测试;付款前确认商户、金额、支付通道和订单描述都符合预期。

本章的完整链路是:
本地 SaaS H5
-> 本机 http://localhost:9220
-> 线上 https://pay-api.example.com
-> 线上 https://pay.example.com/#/hub/{zhcpayToken}
-> 微信 / 支付宝
-> 线上 web-pay 支付网关接收支付平台回调
-> 线上 web-pay 更新支付订单
-> SaaS cloudflared 公网地址
-> 本机 http://localhost:9220/api/pay/notify
-> SaaS 更新业务订单和订阅
重要
🎯 这里有两段回调/通知。 第一段是微信 / 支付宝回调线上 pay-api;第二段是线上 web-pay 通知本机 SaaS cloudflared 地址。web-pay 订单成功但 SaaS 没更新时,通常是第二段出了问题。
打开线上运营平台:
https://paymanager.example.com
检查 web-pay 订单:
支付订单能查到。
金额正确。
商户和应用正确。
支付状态已变成成功或已支付。
通知记录没有持续失败。
再检查 SaaS 业务库:
saas_starter
重点表:
t_saas_pay_order
t_vip_subscription
预期结果:
t_saas_pay_order中对应订单状态已成功。订阅类订单会更新
t_vip_subscription。SaaS 前端刷新后能看到会员、订阅或业务状态变化。
小技巧
🧪 支付成功后,线上运营平台订单成功但本地 SaaS 状态还没更新时,优先看 saas-starter/logs/application-local-tunnel.yml 和 saas-starter/logs/backend.local.log。这通常说明线上 web-pay 已收款成功,但通知本机 SaaS 的公网地址不可达或验签失败。
9.6 失败排查
| 现象 | 优先检查 |
|---|---|
| SaaS 不能创建订单 | saas-starter/logs/backend.local.log、mchNo / appId / AppSecret、线上 pay-api 是否可访问 |
| SaaS 创建订单后没有跳到收银台 | zhcpay.cashier-base-url 是否指向线上收银台、返回的 payUrl 是否存在 |
| 收银台打不开 | 第 8 章 OBS/CDN、HTTPS、CDN 缓存、收银台前端是否为最新构建 |
| 收银台没有支付宝或微信 | 第 6 章支付参数、支付通道、官方产品权限是否启用 |
| 线上运营平台看不到订单 | zhcpay.api-base-url、应用身份、线上支付网关日志、统一下单响应 |
| 支付成功但 web-pay 订单没成功 | pay-api 域名、Nginx、支付平台回调配置、支付网关日志 |
| web-pay 订单成功但 SaaS 没更新 | saas-starter/logs/application-local-tunnel.yml、SaaS tunnel 是否有效、通知地址是否为 /api/pay/notify |
| SaaS 收到通知但业务状态没变 | saas-starter/logs/backend.local.log、t_saas_pay_order、签名校验、订单状态幂等逻辑 |
| SaaS 前端仍显示未支付 | 前端轮询接口、浏览器缓存、业务订单状态、HBuilderX 是否重新运行 |

小技巧
🧪 排查时先判断失败发生在哪一段:本地 SaaS 创建订单、线上支付网关下单、线上收银台展示、微信 / 支付宝付款、线上 web-pay 入账、本机 SaaS 通知。位置分清后,日志会好读很多。
警告
⚠️ 不要在同一轮排查里同时改支付参数、通道、SaaS 身份、前端缓存和 tunnel 地址。一次只改一个变量,重新创建新订单验证,否则很难判断到底是哪一步修好了问题。
9.7 本章完成标准
重要
🎉 这些勾完,基础主线就是 100%。 你已经验证了业务 SaaS、线上 web-pay、支付平台回调和业务状态更新这条链路可以完整跑通。

第 8 章的线上收银台、支付网关、运营平台和运营 API 均可通过 HTTPS 访问。
SaaS 后端已通过
saas-starter/env-scripts/start-local-test-backend.sh启动。saas-starter/logs/application-local-tunnel.yml已生成本次 SaaS 公网通知地址。SaaS H5 已用 HBuilderX 打开
saas-starter/frontend并运行到浏览器。SaaS 能创建订阅、续费或购买订单。
订单能进入线上收银台
https://pay.example.com/#/hub/{zhcpayToken}。收银台能选择支付宝和微信,并能正常展示扫码支付页面。
支付宝或微信可以完成小额扫码支付。
线上运营平台能看到对应支付订单变为成功。
线上 web-pay 能通知本机 SaaS。
SaaS 业务订单和订阅状态同步更新。
已理解:本章完成后,基础教程主线 100% 完成;后续如果要上线
saas-starter或自己的 SaaS,回看第 8 章同一套部署步骤即可。
参见
➡️ 如果你只是学习或交付基础支付能力,完成本章就可以收尾。接下来可以直接基于这套支付底座继续开发自己的 SaaS;等产品功能成熟后,再按第 8 章的方法上线 SaaS 前端、后端和自动发布流程。