7.9 KiB
黄金矿工旧 iOS 客服支付接入
本分支基于现有 wx/KeFuInfo、wx/checkIos 和提供的 order3.html 扩展。未改动游戏前端仓库,未部署或调用真实支付。下载目录中的原文件未修改,可部署副本为 web/order3.html。
客户端和客服入口
- 游戏客户端先以登录态请求
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。价格、用户、期和数量均来自服务端。重复请求复用该玩家该期的订单;原生和客服渠道不允许同一期分别开单。过期或已关闭订单不能继续付款。
- 保存返回的
outTradeNo,将data.sessionFrom原样传入微信openCustomerServiceConversation的sessionFrom。不能继续沿用旧客户端自己生成订单号、拼接价格的黄金矿工路径。票据有效期最多 15 分钟且不超过活动截止;过期后重新预下单取得新票据,不生成另一笔订单。 - 现有客服网关将
FromUserName、SessionFrom转发到wx/KeFuInfo。黄金矿工要求票据签名、归属 openid、商品和环境全部匹配;无需给未知网关新增验签参数。此票据授权向订单本人发送链接,不是付款凭据。普通商品保留现有流程。 - 支付链接参数携带该订单专用
time票据,替代黄金矿工依赖全局iosTime的做法;页面把它原样提交wx/checkIos。也支持游戏内以uid/token/outTradeNo调用该接口。返回严格布尔值true/false。 checkIos只校验和关联订单。order在预下单时就是主记录,iosOrder保留完整兼容副本;主记录存在时不覆盖支付状态,不丢失 goldMiner 快照。主记录缺失时只从已验证的服务端副本恢复。同一操作可重试,付款早于转单也不会回退订单。- 支付成功后,用已有
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.tswx/KeFuInfo.ts、wx/checkIos.tswx/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 请求上下文。