server/laf-cloud/functions/goldMiner/LEGACY-PAYMENT.md
2026-09-24 17:59:52 +08:00

7.9 KiB
Raw Permalink Blame History

黄金矿工旧 iOS 客服支付接入

本分支基于现有 wx/KeFuInfo、wx/checkIos 和提供的 order3.html 扩展。未改动游戏前端仓库,未部署或调用真实支付。下载目录中的原文件未修改,可部署副本为 web/order3.html。

客户端和客服入口

  1. 游戏客户端先以登录态请求 POST /goldMiner/index:
{
  "action": "create_order",
  "channel": "legacy_ios",
  "uid": "玩家ID",
  "token": "登录token",
  "itemid": "当期配置的gold_miner商品ID",
  "createRequestId": "本次购买请求ID"
}

成功外壳为 {code:1,data,msg},data 包含 outTradeNo, periodId, priceFen, productId, quantity:1, channel, expiresAt, sessionFrom。价格、用户、期和数量均来自服务端。重复请求复用该玩家该期的订单;原生和客服渠道不允许同一期分别开单。过期或已关闭订单不能继续付款。

  1. 保存返回的 outTradeNo,将 data.sessionFrom 原样传入微信 openCustomerServiceConversation 的 sessionFrom。不能继续沿用旧客户端自己生成订单号、拼接价格的黄金矿工路径。票据有效期最多 15 分钟且不超过活动截止;过期后重新预下单取得新票据,不生成另一笔订单。
  2. 现有客服网关将 FromUserName、SessionFrom 转发到 wx/KeFuInfo。黄金矿工要求票据签名、归属 openid、商品和环境全部匹配;无需给未知网关新增验签参数。此票据授权向订单本人发送链接,不是付款凭据。普通商品保留现有流程。
  3. 支付链接参数携带该订单专用 time 票据,替代黄金矿工依赖全局 iosTime 的做法;页面把它原样提交 wx/checkIos。也支持游戏内以 uid/token/outTradeNo 调用该接口。返回严格布尔值 true/false。
  4. checkIos 只校验和关联订单。order 在预下单时就是主记录,iosOrder 保留完整兼容副本;主记录存在时不覆盖支付状态,不丢失 goldMiner 快照。主记录缺失时只从已验证的服务端副本恢复。同一操作可重试,付款早于转单也不会回退订单。
  5. 支付成功后,用已有 wx/getPayInfo、wx/iosgetPayInfo 或 wx/getOrderReward 携带 uid/token/outTradeNo 查询。这些接口可触发商户主动查单。返回 rewardDelivery=goldMiner.claim 时进入活动领奖协议;禁止套用普通金币商品的通用补发。

客户端预下单调用是必需接入点,本提交提供后端和页面,未修改 MatchMaster 游戏代码。现有客服网关需原样转发 SessionFrom;仍需微信实际会话联调确认网关没有截断或改写票据。

支付确认与恢复

  • /goldMiner/merchantNotify 是新的 POST 商户通知地址。验证微信支付 RSA 签名和 5 分钟时间窗,AES-256-GCM 解密,再核对 appid、mchid、openid、订单号、CNY 金额、JSAPI 类型和支付时间。
  • 优先读取 ctx.request.rawBody 或 ctx.rawBody。部署必须检查 Laf 网关实际传入的原始体;缺少时只对 JSON.stringify(ctx.body) 的字节尝试验签,若序列化与原消息不同则失败,不绕过验签。主动查单负责恢复遗漏支付。不能仅以接口可访问判定通知已接通。
  • 微信商户查单响应同样需要签名验证。只有可信成功结果能写 confirmedAt/transactionId/paidAt;先持久化支付事实,再授予活动权益。通知只在持久化成功后应答,权益失败交给查单、登录或任务重试。
  • 登录最多查 2 笔待处理订单,任务每轮最多查 5 笔;30 秒订单租约避免重复并发请求,失败退避从 10 秒到最多 5 分钟。网络超时和验签失败保留订单。接口的 PAYMENT_PENDING 不能被当作金币补发授权。
  • 未支付旧期订单经可信查单后关闭;关单与付款竞态会重新查单,成功付款走原活动履约。签名确认延迟时,有达标奖励补发原期,无奖励顺延紧接下一期;重复回调和查询不会重复发资格。冲突保留 manual_review,不自动顺延第三期。
  • goldMiner.paymentChannel 标识 legacy_ios/native,历史缺失该字段的活动订单按原生处理。新增商户快照、预支付状态、租约、重试和支付确认字段均放在原有 goldMiner 对象内,无新增通关事件集合。主订单保留完整原有活动快照。

环境配置和发布

环境变量 内容
PAYMENT_APP_ENV test 或 production,与所在后端和订单一致
GOLD_MINER_LEGACY_ENABLED 仅字符串 true 开放旧渠道预下单和发支付链接,默认关闭;关闭后仍处理已付款订单
WX_MCH_ID 微信支付商户号
WX_MINIGAME_APP_ID 支付 appid,必须与玩家 openid 和商户绑定关系相符
WX_MCH_CERT_SERIAL_NO 商户 API 证书序列号,用于请求签名
WX_PAY_PRIVATE_KEY_BUCKET 私有存储桶,内含 apiclient_key.pem,沿用现有商户签名配置
GOLD_MINER_WECHATPAY_PUBLIC_KEYS JSON 对象:微信支付公钥 ID/平台证书序列号 → 对应 PEM 公钥或证书;与商户私钥不同,支持并存轮换
GOLD_MINER_WECHATPAY_API_V3_KEY 32 字节 API v3 密钥,用于通知解密
GOLD_MINER_ORDER_TICKET_SECRET 随机生成至少 32 字节的服务端票据密钥,测试/正式独立;轮换会使未过期链接失效
GOLD_MINER_MERCHANT_NOTIFY_URL 当前环境的 HTTPS /goldMiner/merchantNotify 完整 URL
GOLD_MINER_PAY_PAGE_URL 实际部署的 HTTPS order3.html 地址,不带 hash
GOLD_MINER_CHECK_IOS_URL 当前环境的 HTTPS /wx/checkIos 完整 URL

依赖已有 cloud.shared 中的 wxaccess_token 和微信有效客服会话;失效时接口返回 CUSTOMER_SERVICE_UNAVAILABLE,复用原订单重试,不递归开单。环境密钥不得放进客户端、Postman 或 Git。

先按 总部署清单 发布依赖和入口,再运行 setup_indexes(包含商户流水唯一索引和查单索引)、绑定每分钟任务、部署支付页,最后启用开关。除 goldMiner 目录外,本次需更新:

  • login.ts
  • wx/KeFuInfo.ts、wx/checkIos.ts
  • wx/getPayInfo.ts、wx/iosgetPayInfo.ts、wx/getOrderReward.ts

如果测试服尚未部署上一版黄金矿工,还必须同步总部署清单中的 userLevel、原生下单、原生回调等文件。现有 YAML 方法未变;专属通知新增 YAML 必须一起发布。

支付页优先使用后端签入链接的 checkUrl,普通旧链接未提供时保留原生产地址。必须部署本仓库副本后才可用测试服链接;Downloads 原页硬编码生产地址。支付页只接受转单接口明确返回 true,并等待 WeixinJSBridge 就绪。小游戏支付参数继续由后端签名。

PAYMENT_APP_ENV=test 只隔离应用和订单,不是微信商户免扣款沙箱;新商户请求仍到微信正式 API。上线前需要实际微信账号验证 appid/openid、客服转发、支付目录/域名、CORS、证书和通知原始体配置,仓库测试无法替代这些部署条件。测试及正式订单的通知地址各自保存在订单快照,不走原生测试回调转发。

验证

node --test laf-cloud/functions/goldMiner/tests/*.test.mjs
node --test --test-name-pattern='gold miner' laf-cloud/tests/login-wucai-state.test.mjs

本地使用模拟数据库、RSA 签名响应和加密通知,未真实支付或发送客服消息。覆盖鉴权/票据、价格、重复预下单、转单快照、付款先于转单、通知验签/解密、查询租约、超时重试、期末关单竞态、跨期履约、支付页及 Postman 链路。Postman 共 42 个请求,新第 07 组测试旧渠道。

参考协议:微信 JSAPI 下单、微信支付通知、Laf 请求上下文。