7.0 KiB
7.0 KiB
name, overview, todos
| name | overview | todos | |||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 虚拟支付沙箱环境自动选择 | 为虚拟支付增加环境自动选择:保持 EnvAppKey/SandboxAppKey 双槽位配置,按「只填沙箱 key → env=1 沙箱;只填现网 key 或两把都填 → env=0 现网」的规则在客户端初始化时决定激活环境,并把 env 贯穿到道具同步、下单签名、订单记录与回调校验全链路。 |
|
产品概述
为微信小程序虚拟支付(XPay)增加环境自动选择能力:配置保留双槽位(EnvAppKey 现网 / SandboxAppKey 沙箱),服务启动初始化时按规则自动判定激活环境,并把 env 贯穿到道具同步、下单签名、查单退款全链路。测试与上线切换只需修改配置文件,无需改代码。
核心功能
- 环境自动选择:只填沙箱 AppKey 时激活沙箱环境(env=1,测试不真实扣款);只填现网 AppKey 或两把都填时激活现网环境(env=0);两把都空时初始化报错、虚拟支付禁用
- 全链路 env 贯穿:道具上传/发布、订单查询/退款、前端调起签名(signData 的 env 字段与 paySig)均使用激活环境的 key 与 env 值
- 订单记录环境:虚拟支付订单的 xpay_env 字段记录下单时的激活环境,发货推送按此校验(沙箱推送不会误发现网订单)
- 环境切换零代码:切换测试/现网只需改配置后重启,启动时的全量道具同步会自动把商品发布到新激活的环境
技术栈
- 语言与框架:Go 1.27(复用现有项目栈,不改架构)
- 涉及模块:pkg/wechat/virtualpay.go(XPay 客户端)、internal/service/virtualpay.go(虚拟支付业务)、pkg/wechat/virtualpay_test.go(单元测试)
- 配置:configs/config.yaml、configs/config.example.yaml(仅更新注释)
实现方案
环境选择规则(初始化时一次决定)
抽成纯函数便于单测:
// resolveEnvKey 按配置决定激活环境:
// EnvAppKey 非空 -> 现网(env=0,两把都填时现网优先);
// EnvAppKey 空且 SandboxAppKey 非空 -> 沙箱(env=1);
// 两把都空 -> 返回错误。
func resolveEnvKey(envAppKey, sandboxAppKey string) (appKey string, env int, err error)
InitVirtualPayClient 调用该函数得到激活 key 与 env:校验 OfferID 非空 + resolveEnvKey 成功;激活 key 存入 client 的 envAppKey 字段(保持 callXPay 签名逻辑不动),新增 env int 字段记录激活环境。日志输出当前激活环境,便于运维确认。
env 贯穿链路
flowchart LR
A[config.yaml<br/>EnvAppKey / SandboxAppKey] --> B[InitVirtualPayClient<br/>resolveEnvKey]
B --> C[client.envAppKey = 激活key<br/>client.env = 0/1]
C --> D[道具同步 API<br/>body 带 env + 沙箱key签名]
C --> E[BuildPaymentSign<br/>signData.env = client.env<br/>paySig 用激活key]
C --> F[QueryOrder / RefundOrder<br/>内部用 client.env]
E --> G[VirtualOrderCreate<br/>订单 xpay_env = GetVirtualPayEnv]
G --> H[发货推送校验<br/>推送 Env == 订单 xpay_env]
关键改动点
pkg/wechat/virtualpay.go
- 新增
resolveEnvKey纯函数(规则见上) virtualPayClient增加env int字段;InitVirtualPayClient改用 resolveEnvKey(原校验改为 OfferID 非空 + 至少一把 key)- 道具 API(StartUploadGoods/QueryUploadGoods/StartPublishGoods/QueryPublishGoods)body 增加
"env": c.env(微信按 env+key 双校验,注释标注字段联调以官方文档为准) QueryOrder/RefundOrder删除 env 入参(当前无 service 调用点,改动安全),内部使用c.envBuildPaymentSign删除 env 入参,signData 的 env 字段与 paySig 使用c.env与c.envAppKey(即激活环境)- 新增导出函数
GetVirtualPayEnv() (int, error)供 service 层记录订单环境
internal/service/virtualpay.go
VirtualOrderCreate:XPayEnv由写死的wechat.XPayEnvProd改为wechat.GetVirtualPayEnv()返回值;BuildPaymentSign调用去掉 env 实参SyncVirtualGoods道具同步调用不变(env 已在 wechat 层内部带入)handleGoodsDeliver的 Env 校验逻辑保持不动(订单 xpay_env 与推送 Env 匹配)
pkg/wechat/virtualpay_test.go
- 适配
TestBuildPaymentSign:client 构造改为含 env 字段、调用去掉 env 实参 - 新增
TestResolveEnvKey:覆盖四个分支(只填现网、只填沙箱、两把都填、两把都空)
配置与文档
configs/config.yaml与configs/config.example.yaml:WechatVirtualPay 段注释更新为环境选择规则(只填沙箱 key 走沙箱测试;只填现网 key 或两把都填走现网)README.md配置表 WechatVirtualPay 行同步该规则
目录结构
pkg/wechat/
├── virtualpay.go # [MODIFY] resolveEnvKey 纯函数、client.env 字段、初始化调整、道具 API 带 env、QueryOrder/RefundOrder 去 env 入参、BuildPaymentSign 去 env 入参、GetVirtualPayEnv
└── virtualpay_test.go # [MODIFY] 适配现有签名测试 + 新增 TestResolveEnvKey 四分支单测
internal/service/
└── virtualpay.go # [MODIFY] VirtualOrderCreate 改用 GetVirtualPayEnv 记录订单环境
configs/
├── config.yaml # [MODIFY] WechatVirtualPay 段注释更新(不改已填值)
└── config.example.yaml # [MODIFY] WechatVirtualPay 段注释更新环境选择规则
README.md # [MODIFY] 配置表 WechatVirtualPay 行说明同步
实现注意事项
- 只改虚拟支付环境选择与 env 贯穿,不动支付架构、权益发放/回退、订单状态机、普通 JSAPI 支付
- 环境切换后重启即可:P0-2 修复后的全量道具同步会自动把商品发布到新激活环境,无需额外迁移
- 沙箱与现网的道具/订单/推送隔离由微信侧保证(按签名 key 与 env 双校验)
- 验证:go build ./...、go vet ./...、go test ./pkg/wechat/ 通过;read_lints 无新增错误