Files
biz-api-cloud-zax/pjcloud-thirdparty/docs/aggregate-h5.md
T
2026-10-28 12:07:11 +08:00

13 KiB
Raw Blame History

双场景聚合支付部署与联调

配置

在 third 服务的 Nacos 配置中增加以下配置。H5 域名由配置提供,不编入 Java 源码;签名密钥需要由部署环境注入至少 32 字节的随机值,不要使用本文或测试中的字符串。

app-plus:
  pay:
    # 网页/移动应用:H5 网页授权与授权码交换使用此组;原 App 支付继续使用此组。
    ali-pay-config:
      app-id: ${ALIPAY_WEB_APP_ID}
      app-private-key: ${ALIPAY_WEB_APP_PRIVATE_KEY}
      alipay-public-key: ${ALIPAY_WEB_PUBLIC_KEY}
      base-callback-url: ${THIRD_PUBLIC_BASE_URL} # 网关公网地址,包含实际 /api 子路径
      pay-callback-url: /third/third-app-pay/app/pay-callback
      refund-callback-url: /third/third-app-pay/app/refund-callback
    # 小程序支付应用:聚合交易创建、付款通知和后续交易处理使用此组。
    ali-pay-mini-config:
      app-id: ${ALIPAY_MINI_APP_ID}
      app-private-key: ${ALIPAY_MINI_APP_PRIVATE_KEY}
      alipay-public-key: ${ALIPAY_MINI_PUBLIC_KEY}
      base-callback-url: ${THIRD_PUBLIC_BASE_URL}
      pay-callback-url: /third/third-app-pay/app/pay-callback
      refund-callback-url: /third/third-app-pay/app/refund-callback
    # 第三方应用独立预留,当前不参与 App/聚合新下单;不用时整组省略。
    # ali-pay-third-party-config:
    #   app-id: ${ALIPAY_THIRD_PARTY_APP_ID}
    #   app-private-key: ${ALIPAY_THIRD_PARTY_APP_PRIVATE_KEY}
    #   alipay-public-key: ${ALIPAY_THIRD_PARTY_PUBLIC_KEY}
    #   base-callback-url: ${THIRD_PUBLIC_BASE_URL}
    #   pay-callback-url: /third/third-app-pay/app/pay-callback
    #   refund-callback-url: /third/third-app-pay/app/refund-callback
    aggregate:
      h5-base-url: https://baac9a029ea84f36ba28c023fed4fc5f.hd.takin.cc
      public-route-prefix: /third # 直接使用 Boot 服务时设为 ""
      merchant-signing-key: ${MERCHANT_COLLECTION_SIGNING_KEY}
      offline-max-amount: 999999 # 整数分,9,999.99 元;提高上限时同时调整 H5 的输入限制
      query-limit-per-minute: 120
      create-limit-per-minute: 30
      trusted-proxy-addresses: []

h5-base-url 只接受 HTTPS 基础地址,不能带查询参数、Hash 或用户信息。可以包含实际部署子路径;H5 的路由 base 需对应配置。

支付宝按网页/移动应用、小程序、第三方应用分类保存配套 AppID、应用私钥和支付宝公钥。H5 不新增应用类型或配置组:授权链接及 alipay.system.oauth.token 使用原 ali-pay-config,聚合 alipay.trade.create 使用 ali-pay-mini-config,两类客户端分别缓存。配置重复 AppID 会造成凭据选择歧义,使用前会明确拒绝。只启用微信的商户不要求支付宝配置;支付宝聚合入口则要求这两组均完整。更新凭据后需重启 third 的全部实例。

新支付单在已有 mch_pay_setting_json 中保存非敏感 alipayAppId,查单、撤销、退款、退款查询及结算/分账按这个 AppID 选择原应用;支付与退款回调先按已登记 AppID 验签,再校验是否与支付单一致。旧快照没有该标识时继续使用原网页/移动应用,不能把历史网页/移动应用订单直接切换到小程序支付应用。本次不增加数据库字段。

仅在网关/反向代理覆盖客户端传入的 X-Real-IP时,将其直连地址加入 trusted-proxy-addresses。默认使用直连 IP 限流。Redis 业务键继续由项目基础设施附加租户前缀,不手工拼接租户编号。

H5 只使用项目根目录一个 .env,变量命名沿用参考 App:开发请求走 VITE_API_URL(默认 /api),由 Vite 代理到 VITE_APP_DEV_SERVICE;生产读取 VITE_APP_PROD_SERVICE。这些后端地址与 H5 页面地址分别配置,不重复附加 /third。VITE_IS_MICRO=true 保留 /third;false 移除前缀,此时后端 public-route-prefix 同时设为 "",确保二维码、OAuth 回调与状态地址也使用 Boot 路径。若线上部署已提供同源接口,生产后端地址可留空。本次未修改实际 Nacos、网关部署或平台控制台。

后端仅为配置的 H5 精确 Origin 开放匿名商户、创建、上下文和状态 JSON 接口的跨域访问,不开放凭据跨域;其他接口保持既有安全规则。

平台配置

  • 微信沿用服务商统一公众号 OAuth 与 JSAPI 下单配置,确认公众号网页授权域名对应现有后端 OAuth 回调域名。
  • 将新 H5 的实际页面目录核对加入微信支付 JSAPI 支付授权目录;Hash 部分不作为目录填写。当前根目录部署对应 https://baac9a029ea84f36ba28c023fed4fc5f.hd.takin.cc/。
  • 支付宝网页授权入口读取 ali-pay-config 的 AppID 与回调基础地址。固定 OAuth 回调为 /third/aggregate-order-pay/oauth/alipay,租户通过一次性 state 恢复;在这个网页/移动应用下配置“授权回调地址”,与该组 base-callback-url + public-route-prefix + /aggregate-order-pay/oauth/alipay 一致。交易创建的异步支付及退款通知地址则读取小程序支付组,通知验签后还需匹配支付单保存的实际下单 AppID。
  • 两种渠道继续使用商户既有支付配置、子商户和默认分佣关系快照,配置需已具备相应 OAuth/JSAPI 权限。仅域名能访问不代表上述平台配置已完成。

支付宝 H5 通过 alipay.trade.create 创建交易并返回 tradeNO,前端使用 AlipayJSBridge.tradePay 调起支付。直付通结算参数沿用现有 ThirdAppPlusAliPayServiceImpl.appPay:始终携带 sub_merchant.merchant_id,以及 settle_info.settle_period_time=1d 和一条 defaultSettle 结算明细;明细金额为交易全额,单位为元,trans_in 留空。关闭平台抽佣仍保留这组结算参数,不在创建交易时扣减平台分佣。

聚合交易创建使用小程序支付组的 JSAPI_PAY;历史聚合快照中的 FACE_TO_FACE_PAYMENT 仍参与严格会话绑定及回调校验,不改写历史流水。原 App 的产品码、SDK 签名下单及默认配置保持不变。支付宝应用类型与产品权限分别管理,不能仅按分类名称认定已获得 API、直付通或当前客户端场景的支付权限。

授权应用与支付应用的用户身份

网页/移动应用用自己的密钥兑换自己发起的授权码,服务端身份对象记录这个来源 AppID;小程序支付不能用其密钥直接兑换另一应用的网页授权码。

跨应用下单只使用 OAuth 实际返回的、2088 开头且共 16 位的 user_id,传入 buyer_id,并要求支付应用当前仍支持该标识模式。如果只返回网页应用的 open_id,后端会拒绝直接向另一个应用传入 buyer_open_id,日志标记为 聚合付款缺少跨应用user_id。仅在身份来源 AppID 与下单 AppID 相同的情况下,才允许直接使用其 open_id。兼容身份构造器未记录来源应用时,也不能据此跨应用使用 open_id。

这意味着两组密钥均已配置仍不等于身份可以互通:若网页授权仅返回 open_id,需核对应用的用户标识模式,或完成支付宝官方支持的应用关联及身份打通;本版本不伪造、推算或擅自转换用户标识,也不依靠前端提供付款人 ID。

直付通关系及渠道联调

直付通关系管理仍归原网页/移动应用;跨应用复用二级商户前,确认两应用属于相同服务商且渠道允许该小程序支付应用使用此 smid。关系中的 app_auth_token 也不能视为自动适用于另一个应用,开启代调用时应核对授权范围。本版本保留既有关系快照及抽佣规则,配置分工本身不会新增渠道权限。

前端仍在支付宝客户端的独立 H5 内通过 AlipayJSBridge.tradePay 调起交易;需以实际支付应用、产品签约、用户标识模式与客户端场景联合验证,不能把当前实现当作任意小程序产品与 H5 容器通用的证明。

参考:支付宝网页授权与授权码交换、支付宝官方聚合 H5/小程序流程对照。当前 SDK AlipayTradeCreateModel.buyerId 文档说明用户号格式及授权来源,身份模式与跨应用能力仍以当前应用实际权限为准。

发布顺序与兼容

  1. 先确认统一支付基线迁移 db/20260825_third_payment_schema.sql 已完成;已完成的环境无需重跑。双场景升级单独执行新文件 db/20261020_add_aggregate_pay_scene.sql,不得只靠修改历史迁移升级现有库。
  2. 新迁移仅新增两个 aggregate_scene 字段,先查字段是否存在,可重复执行;不包含存储过程、字典写入或历史流水回填。业务类型字典 70 = 商户线下收款 可通过管理端配置。
  3. 配置 Nacos 的 H5 地址与随机签名密钥,配套发布 third、wallet 与 H5,再发布后台页面。完整测试与构建由集中验证指令执行。
  4. 商户至少启用并配置完成微信或支付宝其中一个渠道后,即可通过原刷新二维码操作生成新的 URL 收款码。允许仅微信、仅支付宝或双渠道;只校验已启用渠道。新增商户仍先生成原 App Base64 码;没有可用渠道时不生成 H5 码。手动刷新失败会明确反馈并保留原图。
  5. 消费机原 AGGREGATE_ORDER_PAY 类型、二维码路径及内部创建/状态接口保持兼容,OAuth 出口改为 302 到新 H5。原 HTML 渲染器文件保留但不再被 Controller 使用。

数据库字段分别为:聚合会话 aggregate_scene varchar(32) NOT NULL DEFAULT 'ORDER',支付流水 aggregate_scene varchar(32) DEFAULT NULL。线下业务编码是 70,收款请求号由商户和稳定 requestId 派生;不会创建硬件、商城或钱包充值业务订单。

历史聚合会话通过新字段默认值标记为 ORDER;历史支付流水的新字段保持 NULL,本次不做数据回填。

静态 URL 收款码长期有效,HMAC 绑定用途、版本、租户和商户;更换域名或密钥后需重新生成。collectionCode 继续保留 App 协议,collectionUrlCode 仍保存二维码图片地址。

接口与故障恢复

支付宝 E004 授权回调白名单排查

出现 AUTH_REDIRECT_URL_NOT_IN_WHITE 时,先查看 third 的 聚合收银支付宝网页授权 日志。该日志只输出本次实际使用的配置组、appId 和静态 redirectUri,不输出一次性 state、授权码、付款人标识、Token 或密钥。按这两个实际值与同一应用的“授权回调地址”逐项核对,避免拿 Nacos 编辑页面或另一个 AppID 的白名单代替实际请求证据。

若 base-callback-url 为 https://api.example.com/api,微服务前缀为 /third,完整 OAuth 回调就是 https://api.example.com/api/third/aggregate-order-pay/oauth/alipay;不要把网关前缀重复写入基础地址,也不要将 H5 Hash 页面或支付异步通知路径填在授权回调处。确认线上所有 third 实例均已更新配置,并在开放平台修改生效后重新扫码。

  • 匿名查询:GET /third/aggregate-merchant-pay/merchant?id=...&tenantId=...&v=1&sign=...,返回商户 id/name/logoPic 和 supportedPlatforms(10 微信、20 支付宝),不返回支付配置。
  • 线下创建:POST /third/aggregate-merchant-pay/create,提交相同签名参数、整数分 amount 和 UUID requestId。重试不能修改金额或生成新 requestId。
  • 现有聚合入口:/third/aggregate-order-pay/cashier/{tenantCode}/{token}。两个客户端分别进入各自 OAuth;已确认终态的旧请求直接恢复结果页,不再下单。
  • OAuth 回跳只携带短期 ticket,H5 用 /context/{tenantCode}/{ticket} 读取最小渠道参数,用 /status/{tenantCode}/{ticket} 确认结果。票据有效期沿用 5 分钟,付款会话沿用 2 分钟;本机倒计时不能代替服务端查单/关单结果。
  • 取消付款可继续原单;客户端返回成功、未知或网络异常时仍等待服务端确认,不能自行写成功或新建另一笔交易。
  • 缺少 H5 配置时不输出无签名链接;OAuth 入口返回无敏感正文的不可用响应。配置齐全后失败跳固定 H5 错误入口,不反射平台原始异常。
  • H5 扫码客户端不在商户已启用渠道中时,展示专门的提示状态并引导换用已开通 App 扫码,隐藏金额和付款键盘;渠道全部停用时提示联系商户。付款创建和进入 OAuth 前再次检查渠道,前端展示不能替代后端校验。已有渠道子订单继续依据原绑定渠道和配置快照恢复。

本轮未执行实际迁移、修改平台配置或发起真实扣款。集中验证需覆盖微信/支付宝真机、退款和分账、回调验签与重复通知、延迟成功、限流、跨租户及旧消费机状态同步。