Files
junhong_cmp_fiber/docs/feature-034-agent-wallet-qr-recharge/微信扫码支付产品边界核对.md
break 8fc667daee
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m7s
让代理充值复用现有网页支付能力
微信按当前 v2/v3 配置分别生成 MWEB/H5 链接,支付宝复用 C 端 WAP 链接,并让可用支付方式基于生效配置判断。

Constraint: 支付链接统一通过 qr_content 返回,由前端渲染二维码;按要求不运行测试

Rejected: 微信 Native 与支付宝当面付 | 会引入非当前商户配置所需的额外产品开通

Confidence: high

Scope-risk: moderate

Directive: 微信 H5/MWEB 二维码仅承诺系统相机或外部浏览器扫码链路

Tested: 相关 Go 包编译通过;gofmt 与 git diff --check 通过

Not-tested: 按用户要求未运行自动化测试及真实支付联调
2026-07-30 11:41:50 +08:00

9.8 KiB
Raw Blame History

微信扫码支付产品边界核对

结论

  1. 微信支付产品和接口协议版本是两个不同维度:JSAPINativeH5 是支付产品/用户场景API v2、API v3 是商户后台调用微信支付的协议版本。
  2. 桌面代理后台展示二维码、用户拿手机微信扫码支付,应使用 Native 支付。Native 下单返回 code_url,前端把它生成二维码。这正是微信官方定义的扫码支付场景。
  3. JSAPI 确实可以正常支付,但它要求支付页面运行在微信内置浏览器中,并取得当前用户 openid然后由页面调用微信支付控件它不是“PC 页面展示二维码供另一台手机扫码”的产品。
  4. H5 支付用于手机浏览器非微信客户端内跳转拉起微信v2 返回 mweb_urlv3 返回 h5_url。这两个 URL 在技术上当然都能编码成二维码;但能否支付取决于扫码后打开它的浏览器环境。微信“扫一扫”会在微信内置浏览器打开,而官方 H5 支付明确面向微信客户端外的浏览器,因此不能把这条路径当作可用的微信扫码支付流程;系统相机或其他扫码工具若把链接交给手机外部浏览器,则可能按 H5 流程拉起微信,但仍须满足支付域名、Referer 等官方校验。
  5. 微信支付的能力并非天然“只接受 v3”。官方 API v2 的统一下单用 trade_type=JSAPI/NATIVE/MWEBAPI v3 则分别提供 JSAPI、Native、H5 下单接口两代协议都覆盖这三类产品。实际能否调用还取决于商户是否开通对应产品、AppID 与商户号绑定等平台条件。
  6. 项目已按最终产品决定支持两种当前配置:provider_type=wechat 调用 v3 H5provider_type=wechat_v2 调用 v2 MWEB两者分别返回 h5_urlmweb_url,统一映射为 qr_content

产品边界

产品 官方适用场景 下单主要返回物 客户端完成支付方式 是否适合本需求
JSAPI 用户已经在微信客户端内打开商户网页 prepay_id;商户再生成前端调起支付所需参数 页面调用微信支付控件,且需传用户 openid 否。除非把代理充值页改成微信内页面并增加 OAuth/OpenID 链路
Native PC 网站、实体物料等展示二维码,用户使用微信“扫一扫” code_url 商户把 code_url 生成二维码,用户扫码 是,和当前需求完全匹配
H5v2 名称 MWEB 用户在手机系统浏览器等微信客户端外的移动网页发起支付 h5_urlv2 返回字段为 mweb_url 当前手机浏览器跳转该 URL 拉起微信 有条件可用:系统相机/外部扫码工具进入外部浏览器时可能完成;微信“扫一扫”进入微信内置浏览器时不符合官方 H5 场景

因此“JSAPI 能正常支付”和“它适合桌面扫码”并不矛盾:前者描述支付能力,后者描述用户入口。选型依据应是入口场景,而不是某一种产品是否能够完成扣款。

mweb_url / h5_url 生成二维码后的准确边界

先区分两件事:前端二维码组件可以渲染任意 URL这只证明二维码可以被识别是否能完成支付由微信支付产品规则和扫码后的浏览器环境决定。API v2 的 mweb_url 与 API v3 的 h5_url 在这一点上没有产品语义差异,都是 H5 支付跳转地址。

扫码入口 实际打开环境 官方产品边界 结论
微信“扫一扫” 微信内置浏览器 微信官方将 H5 支付定义为在微信客户端外的移动浏览器中调起微信支付 二维码能识别、URL 也能打开,但不能据此认定 H5 支付可完成;这不是官方支持的 H5 入口
系统相机、系统扫码器或其他把链接交给浏览器的工具 Safari、Chrome 等微信外部移动浏览器 符合 H5 支付的浏览器场景;浏览器跳转 mweb_url/h5_url 后拉起微信 可以作为 H5 跳转方式,但必须满足商户已开通 H5、支付域名配置、请求来源等校验

还有一个容易遗漏的限制:官方开发指引要求 H5 调起链路携带符合配置的 Referer,微信支付中间页会进行 H5 权限和安全校验。因此,将下单返回的裸 mweb_url/h5_url 直接编码进二维码,会让最终行为依赖扫码工具如何打开链接、是否保留合法来源;它不像 Native 的 code_url 那样是官方专门定义的“生成二维码后由微信扫码”凭据。更稳妥的 H5 二维码做法是二维码指向商户自己的已配置 H5 页面,再由该页面在外部浏览器中跳转微信返回的 H5 地址。

所以用户提出的说法应修正为:mweb_url/h5_url 可以由前端渲染成二维码,系统相机扫码后进入外部浏览器时有条件可支付;但微信“扫一扫”打开的是微信内置浏览器,不满足官方 H5 支付场景。若产品要求用户明确使用微信扫一扫,仍应使用 Native code_url

API v2 与 API v3

官方能力

  • API v2 使用统一下单接口,通过 trade_type 区分产品:JSAPINATIVEMWEB。对应返回分别围绕 prepay_idcode_urlmweb_url
  • API v3 将三类下单拆成独立接口:
    • JSAPIPOST /v3/pay/transactions/jsapi,返回 prepay_id
    • NativePOST /v3/pay/transactions/native,返回 code_url
    • H5POST /v3/pay/transactions/h5,返回 h5_url

所以正确表述是:v2 和 v3 都可以承载 JSAPI、Native、H5/MWEB项目是否支持取决于对应协议分支有没有实现该产品的下单、签名、查单、关单和回调验签。

本项目当前实现

  1. WechatConfig.ProviderType 明确把 wechat 定义为 v3、wechat_v2 定义为 v2同一条配置模型同时有 wx_api_v3_key、证书/私钥/序列号和 wx_api_v2_key 字段。
  2. 通用加载器按 provider_type 选择实现:
    • wechat 构建 PowerWeChat v3 服务;
    • wechat_v2 构建本地 XML+MD5 v2 服务。
  3. v3 服务目前实现 JSAPI 和 H5仓库曾有/SDK具备 Native 调用能力,但当前代理充值 Adapter 调的是 CreateH5Order -> TransactionH5,把返回的 H5URL 放入 QRContent
  4. v2 服务保留 JSAPI并已增加 trade_type=MWEB 下单、mweb_url 解析和 v2 查单;通用 v2 Adapter 同步开放 H5/MWEB 与查单能力。
  5. GET /api/admin/agent-recharges/payment-methods 读取唯一生效配置,再调用 Adapter 的 Availablev3 校验 v3 Key、证书和序列号v2 校验 APIv2Key两种配置均可返回 wechat

因此测试环境生效配置为 provider_type=wechat_v2 且 APIv2Key、商户号、AppID 和回调地址完整时,接口会返回 wechat,创建时使用 MWEB。

“基于当前支付配置”的准确含义

“基于当前支付配置”不等于“看到哪组密钥非空就自动尝试哪套协议”。当前代码的配置解析规则是:

唯一 is_active=true 的 WechatConfig
        │
        ├─ provider_type=wechat    → 选择 v3 实现 → 校验 v3 凭据
        ├─ provider_type=wechat_v2 → 选择 v2 实现 → 校验 APIv2Key
        └─ provider_type=fuiou     → 选择富友实现

也就是说,字段值提供凭据,provider_type 决定协议和 Adapter。即使同一行同时填了 v2、v3 字段,代码也不会自动降级或跨协议尝试。支付宝字段则是同一配置行中的并存能力,当前可用性判断不通过 provider_type=alipay 分流。

本项目最终采用方式

用户已确认接受“系统相机或外部扫码工具打开手机外部浏览器”的 H5/MWEB 使用方式,项目据此采用:

  1. provider_type=wechat:调用 v3 H5 下单和查单,返回 h5_url
  2. provider_type=wechat_v2:调用 v2 MWEB 下单和查单,返回 mweb_url
  3. 两个分支继续使用各自协议的回调验签;支付 URL 统一保存并返回为 qr_content
  4. 前端负责渲染二维码,同时明确提示使用系统相机或外部浏览器扫码;本方案不承诺微信“扫一扫”入口。

仓库证据

  • internal/model/wechat_config.gowechat/wechat_v2 的协议含义及两套密钥字段。
  • pkg/payment/loader.go:按 provider_type 构建 v3 或 v2 服务v2 Adapter 转发 JSAPI、H5/MWEB 与查单。
  • pkg/wechat/payment_v2.gov2 XML+MD5 的 JSAPI、MWEB 下单与查单实现。
  • pkg/wechat/payment.gov3 JSAPI 返回 prepay_id/pay_configH5 返回 h5_url
  • internal/infrastructure/payment/wechat_web.go:代理充值按 provider_type 调用 v3 H5 或 v2 MWEB并把支付 URL 写入 QRContent
  • internal/application/agentrecharge/online_creation.go:支付方式接口读取 is_active=true 配置,并只返回 Adapter 判定可用的方式。

微信支付官方来源

核对日期2026-07-30。上述来源均为微信支付官方域名旧版 API v2 文档可能由官方站点重定向到新版文档中心,但其统一下单字段和产品语义也可由仓库现有 v2 实现交叉核对。