14 KiB
双场景聚合支付部署与联调
配置
在 third 服务的 Nacos 配置中增加以下配置。H5 域名由配置提供,不编入 Java 源码;签名密钥需要由部署环境注入至少 32 字节的随机值,不要使用本文或测试中的字符串。
app-plus:
pay:
# 网页/移动应用:聚合支付宝 WAP 签名及付款通知;原 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
# 小程序及历史小程序交易凭据:当前 H5 新下单不读取此组;已有相关流水时保留原凭据。
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、应用私钥和支付宝公钥。新支付宝聚合付款使用现有 ali-pay-config 的 alipay.trade.wap.pay 手机网站支付能力,产品码为 QUICK_WAP_WAY,不再先取网页 OAuth 身份,也不调用 alipay.trade.create。网页/移动应用需要已开通手机网站支付及实际直付通商户收单权限,切换凭据不会自动开通产品。没有新增 ali-pay-h5-config。原 App 默认配置与 app.pay 路径保持兼容。聚合支付宝旧 OAuth、alipay.trade.create 和 H5 tradeNO 调起代码已删除。
新支付单在已有 mch_pay_setting_json 中保存网页应用的非敏感 alipayAppId,查单、关单、退款、退款查询及结算/分账按这个 AppID 选择原应用;支付与退款回调先按已登记 AppID 验签,再校验是否与支付单一致。历史小程序流水仍按其快照选择原小程序凭据;旧快照没有该标识时继续使用原网页/移动应用。只启用微信的商户不要求支付宝配置。更新凭据或切换下单应用后需重启 third 的全部实例。本次不增加数据库字段,不改写历史订单。
仅在网关/反向代理覆盖客户端传入的 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的手机网站支付产品及直付通权限,异步支付和退款通知也读取此组。核对base-callback-url + pay-callback-url指向公网可达的原验签通知接口。 - WAP 支付完成或退出地址为服务端生成的
base-callback-url + public-route-prefix + /aggregate-order-pay/return/alipay/{tenantCode}/{ticket}。这一入口只做固定 302,回到同一 H5 票据并附加returned=1;不能把它填作异步通知,更不能凭浏览器回跳参数判断付款成功。按当前应用平台要求配置实际网站域名及返回地址。 - 聚合支付宝不再提供
/third/aggregate-order-pay/oauth/alipay授权回调,也不读取买家 OAuth 身份;微信 OAuth/JSAPI 保持原路径与语义。 - 两种渠道继续使用商户既有支付配置、二级商户和默认分佣关系快照,不因新增 WAP 路径改变收款方或结算归属。
支付宝手机网站支付流程
- 用户在支付宝扫码后进入商户 H5,输入金额或查看订单固定金额。原聚合
/cashier/{tenantCode}/{token}入口识别支付宝客户端,对新会话使用无 OAuth 的 WAP 平台绑定;同一会话的 CAS 只分配一个支付单号,不伪造付款人 ID。已绑定付款人摘要的历史支付宝会话只签发只读结果票据,不创建第二笔 WAP,也不再输出旧 tradeNO 调起参数。 - 后端通过 SDK
pageExecute(request, "GET")本地签名alipay.trade.wap.pay,先保存本地流水及请求/调起快照,再交付收银票据。完整签名地址使用现有统一加密器保存,仅在短期票据上下文中解密返回,避免 SQL 日志和后台流水明文泄漏。这一步不会远程创建支付宝交易,不返回业务 HTML。H5 的launchParams为{ mode: "ALIPAY_WAP", payUrl: "https://openapi.alipay.com/gateway.do?..." };微信调起字段保持兼容,支付宝不再接受tradeNO旧调起模式。 - H5 首次进入票据页后只自动调起一次,严格校验官方网关的协议、主机、路径和 API,再导航支付宝收银台。签名 URL 只保存在内存,不写入二维码、H5 Hash 或浏览器恢复存储。手动继续会先重新读取上下文,确认原单仍可支付。
- 支付完成、退出或浏览器返回后查询原单,返回提示只用于抑制重复自动导航;成功仍由验签通知或后端查单确认。网络失败、取消、刷新均保留金额和 requestId,不能新建第二个可支付请求。
WAP 的直付通结算参数沿用原 App 路径:sub_merchant.merchant_id、settle_info.settle_period_time=1d 及交易全额的 defaultSettle 明细,金额为元,trans_in 留空;仅开启平台抽佣且商户配置了代调用授权时携带 app_auth_token。关闭抽佣也必须保留二级商户和全额结算参数。签名日志仅记录配置组、AppID、API、产品码和业务支付单号,不记录签名 URL、授权令牌或用户身份。
会话和签名请求共用原两分钟绝对截止时间。WAP 使用 time_expire,不使用最小五分钟的 timeout_express;首次签名余期不足一分钟时拒绝请求,不能续期。有效期内查无此单只表示用户尚未访问网关,不能确认关闭。到期且支付宝明确返回 ACQ.TRADE_NOT_EXIST 才可按未建单结束;网络、权限及未知错误继续阻止新交易。已存在的 WAP 未支付交易使用 alipay.trade.close,关单失败再次查单以处理付款竞态,避免用 cancel 自动退款已成功交易。历史 JSAPI 的处理保持原逻辑。
回调快照分类同时接受 QUICK_WAP_WAY、历史 JSAPI_PAY 和 FACE_TO_FACE_PAYMENT,仍严格验证原应用、会话、业务、商户和金额。WAP 按到期查无单本地关闭时,在原响应 JSON 中记录 wapClosedWithoutTrade=true;只有这一类本地关闭允许迟到的已验真成功通知原子恢复成功,渠道真实关闭、退款等终态不能据此恢复。原 App 不改用 WAP,退款和分账仍按原交易应用及商户关系处理。
参考:手机网站支付接入流程、手机网站支付产品及辅助接口。签名请求不代表已付款,实际权限、直付通结算及微信/支付宝真机行为仍须集中联调确认。
发布顺序与兼容
- 先确认统一支付基线迁移
db/20260825_third_payment_schema.sql已完成;已完成的环境无需重跑。双场景升级单独执行新文件db/20261020_add_aggregate_pay_scene.sql,不得只靠修改历史迁移升级现有库。 - 新迁移仅新增两个
aggregate_scene字段,先查字段是否存在,可重复执行;不包含存储过程、字典写入或历史流水回填。业务类型字典70 = 商户线下收款可通过管理端配置。 - 配置 Nacos 的 H5 地址与随机签名密钥,配套发布 third、wallet 与 H5,再发布后台页面。完整测试与构建由集中验证指令执行。
- 商户至少启用并配置完成微信或支付宝其中一个渠道后,即可通过原刷新二维码操作生成新的 URL 收款码。允许仅微信、仅支付宝或双渠道;只校验已启用渠道。新增商户仍先生成原 App Base64 码;没有可用渠道时不生成 H5 码。手动刷新失败会明确反馈并保留原图。
- 消费机原
AGGREGATE_ORDER_PAY类型、二维码路径及内部创建/状态接口保持兼容,OAuth/WAP 收银出口均为 302 到新 H5。已删除无人调用的旧 HTML 收银渲染器及其支付宝 JSAPI 专用测试,Controller 统一 302 到独立 H5。
数据库字段分别为:聚合会话 aggregate_scene varchar(32) NOT NULL DEFAULT 'ORDER',支付流水 aggregate_scene varchar(32) DEFAULT NULL。线下业务编码是 70,收款请求号由商户和稳定 requestId 派生;不会创建硬件、商城或钱包充值业务订单。
历史聚合会话通过新字段默认值标记为 ORDER;历史支付流水的新字段保持 NULL,本次不做数据回填。
静态 URL 收款码长期有效,HMAC 绑定用途、版本、租户和商户;更换域名或密钥后需重新生成。collectionCode 继续保留 App 协议,collectionUrlCode 仍保存二维码图片地址。
接口与故障恢复
历史支付宝交易
移除旧下单入口不删除历史支付流水、应用快照或小程序凭据。JSAPI_PAY、FACE_TO_FACE_PAYMENT 等已有聚合流水仍参与严格回调验签、金额/商户/会话匹配,并按原应用进行查单、撤销、退款和分账。旧会话不会改为新 WAP 交易,也不会因删除创建接口而直接写成功或关闭。历史支付宝 OAuth 回调地址不再对外提供,新聚合付款无需网页授权。
- 匿名查询:
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}。支付宝新会话进入 WAP,微信继续 OAuth,历史已绑定身份的支付宝会话仅查询原支付结果;已确认终态的旧请求直接恢复结果页,不再下单。 - 收银回跳只携带短期 ticket(WAP 返回额外带无状态语义的
returned=1),H5 用/context/{tenantCode}/{ticket}读取最小渠道参数,用/status/{tenantCode}/{ticket}确认结果。票据有效期沿用 5 分钟,付款会话沿用 2 分钟;本机倒计时不能代替服务端查单/关单结果。 - 取消付款可继续原单;客户端返回成功、未知或网络异常时仍等待服务端确认,不能自行写成功或新建另一笔交易。
- 缺少 H5 配置时不输出无签名链接;收银入口返回无敏感正文的不可用响应。配置齐全后失败跳固定 H5 错误入口,不反射平台原始异常。
- H5 扫码客户端不在商户已启用渠道中时,展示专门的提示状态并引导换用已开通 App 扫码,隐藏金额和付款键盘;渠道全部停用时提示联系商户。付款创建和进入渠道收银前再次检查渠道,前端展示不能替代后端校验。已有渠道子订单继续依据原绑定渠道和配置快照恢复。
本轮未执行实际迁移、修改平台配置或发起真实扣款。集中验证需覆盖微信/支付宝真机、退款和分账、回调验签与重复通知、延迟成功、限流、跨租户及旧消费机状态同步。