技能学习
Sep 07, 2026

易支付网关接入复盘:从「签名失败」到全链路稳定

支付网关 · 复盘笔记

易支付网关接入复盘:从「签名失败」到全链路稳定

mailsorta-worker(Cloudflare Workers)· 2026-09-05 ~ 09-07
范围:mailsorta-worker(Cloudflare Workers 商用邮件整理 SaaS)接入易支付网关的完整过程,2026-09-05 至 2026-09-07。证据来源:期间沟通记录、线上代码(src/payment/epay.ts、src/api/billing.ts)与线上实测。目标读者:本项目维护者,以及任何计划在 Workers / Serverless 上接入易支付的开发者。

🎯 目标与预期

目标:在 Cloudflare Workers 上接入易支付,支持四种通道(支付宝 alipay、微信 wxpay、USDT gmpay、Stripe fiatstripe),美元直接计价收款,支付成功后自动开通会员。

原计划假设:按「标准彩虹易支付」协议接入——&key= 前缀签名、下单金额严格校验、仅监听 POST 回调。预期一次打通、无需返工。

📅 事件时间线

时间 事件 结果 关键学习
09-05初版接入:四通道、USD+每日汇率表、验签+金额校验+幂等+主动查单本地测试通过Workers 运行时无 MD5,需引入 [email protected] 并封装
09-06用户澄清:美元直收,移除全部 USD→CNY 汇率换算删除汇率表/汇率刷新任务/KV 缓存通道自带汇率换算时,商户侧无需维护汇率
09-06「配置了商户但还是签名失败」4 种签名变体实测,定位 payone.uk 需 direct 模式不同易支付站点签名协议不同,不能写死
09-06支付成功但会员状态未更新修复金额校验容差 + 回调多形态兼容 + 主动查单金额校验要兼容通道汇率换算;回调不可靠需双通道
09-06订单展示与支付页品牌化默认 5 条+查看更多、四通道品牌图标
09-07全项目源码审查支付链路确认无问题兜底设计(查单+幂等+前端轮询)有效

🔍 聚类观察:四类坑与修复

签名模式不统一(最耗时)

现象:管理后台已配置商户号与密钥,下单仍报「签名失败」。

诊断过程:对签名做了 4 种变体逐一实测(&key= 前缀 / 直接拼接 / 排序差异 / 大小写差异),用 curl 跟随重定向验证收银台是否接受。确认本项目所用的易支付站点 payone.uk 采用 direct 模式:按参数名 ASCII 字典序拼接 k=v&... 后,直接拼接密钥再做 MD5,而非标准彩虹易支付的 &key=密钥 前缀。

修复:epay.ts 增加 sign_mode 字段,epaySign / verifyNotify 支持 standard / direct 双模式;管理后台新增「签名模式」下拉;下单与验签均按所选模式执行。

💡 易支付是共享协议、多站点实现,签名规则必须做成可配置项,不能按单一站点写死。上线新站点前先跑一次签名自测。

金额校验过严,回调被误拒

现象:支付成功、回调也到达,但会员状态未更新。

根因:订单以 USD 计价(实测订单 4.99 USD),易支付通道在收款时按自身汇率换算成 CNY(同一笔订单通道收款 34.43 CNY)。初版 notify 按 price_usd ±0.02 严格校验,换算后的回调金额必然被拒收。

修复:金额校验放宽为容差窗口校验(按通道换算逻辑允许合理倍率偏差),并辅以主动查单确认真实支付状态。

💡 只要标价货币与通道结算货币不同,回调金额 ≠ 下单金额就是常态。金额校验必须留容差;精确对账交给查单接口,而不是回调金额。

回调只监听 POST,存在漏单窗口

现象与根因:初版只处理 POST JSON 回调,不同易支付站点可能以 GET 或表单(x-www-form-urlencoded)形式通知。

修复:notify 端点统一兼容 GET / POST / JSON / 表单四种形态;订单保持 pending 超过 30 秒时,主动调用 api.php?act=order 查单兜底。

💡 支付通知是不可靠通道,正确姿势是「异步回调 + 主动查单」双通道,而不是依赖回调单一形态。

履约非幂等,重复回调有风险

修复:将「开通会员」抽成 fulfillOrder(),以订单状态为唯一权威:仅 pending → paid 才履约;重复回调直接返回成功,不重复累加会员时长。

回跳闭环:return_url 带回 out_trade_no,前端从 #/billing?pay=... 解析后轮询订单状态,支付成功后自动刷新会员信息。

📖 签名协议对比(保留的核心知识)

对比维度 standard(彩虹易支付) direct(payone.uk 等)
参与签名参数去除 sign、sign_type 与空值同左
排序参数名 ASCII 字典序同左
拼接k=v&...&key=商户密钥k=v&... 后直接拼接密钥(无 &key= 前缀)
摘要与比对MD5,转小写比对同左
适用站点传统彩虹易支付站点payone.uk 等新站点

💱 金额与计价的取舍

版本 计价与校验 问题 结论
v1USD+每日汇率表;回调按 price_usd ±0.02 严格校验汇率刷新任务与 KV 缓存复杂;回调金额按通道汇率换算后必然对不上商户侧不应维护汇率
v2USD 直收,money=price_usd 原样下单;回调改容差窗口校验通道自带汇率换算时直接透传,校验留容差

💭 洞见与待验证假设

洞见:易支付这类「共享协议聚合站」的接入风险不在协议文档,而在各站点的实现差异;把差异参数化(sign_mode、api_url、pay_types 均可配置)比逐站写适配代码更省。

洞见:支付闭环的可靠性排序为「幂等履约 > 主动查单 > 多渠道回调 > 前端提示」,资源应按这个优先级投入。

待验证假设:payone.uk 的 direct 模式是否代表该平台所有商户的统一行为——目前仅凭本项目一个商户号的实测,样本为 1;后续接入新商户或新站点时应先跑一次签名自测再上线。

✅ 保留项(这套设计继续沿用)

管理后台全参数化:api_url / pid / key / 支付方式勾选 / 签名模式,均不进代码,开源分发零改码。

下单与回调共用同一签名函数,避免两处实现漂移。

订单表记录 price_usd / out_trade_no / 通道单号,管理后台可按状态筛选。

Workers 无 MD5 的坑已用 [email protected] 补齐并封装在 src/crypto/md5.ts。

🧪 改进实验(下一轮验证)

实验 动作 验证条件 跟踪位置
新站点接入自测接入第二个易支付商户或站点时,先跑签名自测脚本再上线首笔订单支付+回调全链路通过项目 docs/ 支付复盘文档
对账告警订单已 paid 但超过 5 分钟未履约时,管理后台标记异常异常单可被后台发现并手动补单管理后台订单状态
回调失败重试notify 处理失败时返回非 2xx,触发通道自动重推观察通道重推日志,最终履约成功同步/履约日志旁路

🔁 复查

本轮复盘覆盖 09-05 至 09-07 全部支付相关改动,结论均回链当时沟通记录与线上代码;「改进实验」中的三项均为可验证动作,下一次接入新支付站点时按实验一执行。

评论区

0 条评论 · 评论需审核通过后显示

加载评论中...

发表评论

0/2000

← 返回
🔍
客服图标
微信客服图标
🤖
×

微信客服

微信二维码