Harmony Next使用payInterceptorWithUrl拦截H5支付提示系统繁忙
结论
出现”系统繁忙,请稍后重试”,通常并不是 Harmony Next 系统繁忙,而是支付宝客户端无法校验收到的支付请求。结合示例地址,建议优先检查以下问题:
- 支付 URL 中可能包含空格:
.../notify/alipayWa /xxxxxxxxxxx。 - 拦截 URL 后,程序在将其传给
payInterceptorWithUrl前做了解码、重新编码、拼接或截断,导致原始参数与签名不匹配。 - 收银台返回的是旧版
mapi.alipay.com/gateway.do请求,其订单参数、签名方式或商户配置可能已经失效。 - H5 收银台与支付宝客户端或 SDK 之间出现兼容性问题。
支付宝 App 10.7.36、支付宝 SDK 15.8.36 和 Harmony ArkTS SDK 12 都可以作为排查条件,但不能仅凭版本号认定是哪一方的问题。应先验证原始支付 URL 和订单参数,再检查拦截逻辑。
首先检查支付 URL
示例地址中的这一段需要重点确认:
notify_url=https://fingw.test.pajk.cn/notify/alipayWa /xxxxxxxxxxx
^
如果这个空格确实存在,并非复制或脱敏时引入的格式问题,那么 URL 本身已经不合法,可能导致:
notify_url被截断;- 后续参数被错误并入
notify_url; - 支付宝验签失败;
- 商户订单参数解析失败;
- 客户端最终只显示通用的”系统繁忙”。
不要直接删除空格后继续支付,因为这些支付参数通常已经参与签名。应让收银台服务端重新生成完整、没有空格且签名一致的支付 URL。
还要确认 /xxxxxxxxxxx 是否只是脱敏内容。如果它实际代表其他查询参数,参数之间必须用 & 连接,不能直接拼在 notify_url 后面。
正确的结构应类似:
https://mapi.alipay.com/gateway.do?_input_charset=utf-8&it_b_pay=1440¬ify_url=https%3A%2F%2Fexample.com%2Fnotify&out_trade_no=...&sign=...
这只是结构示意,不能用它补造真实订单参数。
保持拦截前后的 URL 完全一致
支付 URL 通常包含已经编码的参数和签名。下面这些操作都可能破坏订单:
- 对整个 URL 调用
decodeURIComponent; - 解码后再调用
encodeURIComponent; - 将 URL 解析成对象后重新拼接;
- 使用普通对象保存参数,导致参数顺序改变;
- 将
+转为空格; - 提前还原
%2F、%3D等转义字符; - 没有将 HTML 实体
&正确转换为&; - 从页面文本中提取 URL,而不是读取导航请求;
- URL 在日志记录、消息传递或字符串切片时被截断。
拦截时,应保留 WebView 给出的原始请求地址,并把同一个字符串交给支付宝 SDK:
function handleNavigation(rawUrl: string): boolean {
if (!isAlipayPaymentUrl(rawUrl)) {
return false;
}
// 不要对 rawUrl 解码、排序参数或重新拼接。
startAlipayPayment(rawUrl);
return true;
}
function isAlipayPaymentUrl(url: string): boolean {
try {
const parsed = new URL(url);
return parsed.protocol === 'https:' &&
parsed.hostname === 'mapi.alipay.com' &&
parsed.pathname === '/gateway.do';
} catch (_) {
return false;
}
}
调用 SDK 时也应直接传入原始地址:
function startAlipayPayment(rawUrl: string): void {
// payInterceptorWithUrl 的参数形式和回调类型,
// 以项目实际引入的 HarmonyOS 支付宝 SDK 声明为准。
alipay.payInterceptorWithUrl(rawUrl, true, (result) => {
console.info(`Alipay result: ${JSON.stringify(result)}`);
});
}
具体封装名称不是重点。需要保证的是,传入 payInterceptorWithUrl 的内容与 WebView 拦截到的原始 URL 完全相同,不能用处理后的 URL.toString() 结果替代。
建议的排查顺序
1. 对比拦截前后的原始字符串
分别记录以下信息:
WebView 实际请求的原始 URL
传入 payInterceptorWithUrl 的 URL
URL 长度
是否包含空格、换行、制表符或 NUL 字符
日志中如果涉及 sign、订单号、用户信息等敏感参数,必须做脱敏处理。不要只靠肉眼比较格式化后的 URL,最好同时比较长度,或者对完整字符串计算摘要。
function inspectPaymentUrl(url: string): void {
console.info(`urlLength=${url.length}`);
console.info(`hasWhitespace=${/[\s\u0000]/.test(url)}`);
}
如果拦截前后的长度不同,或者字符串中出现空白字符,应先修复 URL 的传递链路。
2. 绕过拦截逻辑做对照测试
用同一笔新生成的测试订单进行对照:
- 在未接入
payInterceptorWithUrl的环境中打开收银台; - 在其他已经验证的平台或浏览器中完成唤起;
- 在 Harmony Next 中拦截 URL,并将其传给支付宝 SDK。
如果所有环境都失败,问题更可能出在收银台服务端、订单参数或商户配置上。如果只有 Harmony Next 拦截后失败,应重点检查 URL 是否被修改,以及 SDK 的调用时机。
不要反复使用同一个支付地址测试。部分订单可能已经过期、关闭、完成支付,或者只能使用一次。
3. 让收银台供应商检查服务端订单
供应商应根据支付宝返回的实际错误信息核对:
app_id、partner、卖家账号等商户身份是否一致;- 订单号是否重复;
- 订单是否已经关闭或过期;
it_b_pay=1440的单位和有效期是否符合所用接口的要求;notify_url是否为合法、完整且可以访问的 HTTPS 地址;service、payment_type、金额和签名参数是否完整;sign_type是否与实际使用的签名算法一致;- 商户密钥、证书或应用授权是否发生过变更;
- 签名时使用的参数值,是否与最终写入 URL 的值完全相同;
- 是否仍在使用不适合当前业务的新旧接口组合。
mapi.alipay.com/gateway.do 是较早期的支付宝网关形式。是否需要迁移接口,应由收银台供应商根据其签约产品和支付宝当前接入规范确认,不能只替换域名或接口名称。
4. 获取支付宝侧可用于定位问题的信息
“系统繁忙”只是客户端显示的通用文案,无法据此判断根因。排查时应收集:
- 失败发生的准确时间;
- 商户订单号;
- 支付宝交易号(如果已经生成);
- 商户应用或合作伙伴标识;
- 支付 URL 中经过脱敏的参数清单;
- SDK 回调结果;
- 支付宝客户端日志或问题反馈编号;
- 能够稳定复现问题的测试订单。
如果服务端已经收到支付宝网关响应,应优先查看其中的错误码、子错误码和错误描述,不要只根据 App 页面上的提示判断。
版本兼容性排查
建议至少测试以下组合:
- 当前支付宝 App
10.7.36; - 能够获得的其他支付宝 App 版本;
- 当前 SDK
15.8.36; - 经支付宝官方确认支持 Harmony Next 和 ArkTS SDK 12 的 SDK 版本;
- 不同设备和不同系统补丁版本。
如果同一订单只在某个支付宝 App 或 SDK 版本组合下失败,可以整理最小复现材料并提交给支付宝技术支持。但在确认 URL 完整性和服务端验签结果之前,不宜直接认定为版本兼容问题。
注意事项
- 不要在客户端修改金额、订单号、回调地址或其他已经签名的字段。
- 不要为了去掉空格而单独替换字符串,应由服务端重新生成参数并签名。
- 拦截成功后,应阻止 WebView 再次加载同一支付地址,以免重复唤起。
- 拦截规则应同时校验协议、主机名和路径,不能只判断字符串是否包含某段内容。
- 不要把完整的支付 URL 写入生产日志。
- 如果多个供应商近期同时出现问题,应比较它们是否共用了同一个收银台服务、旧接口、URL 转换组件或签名组件。
目前最需要优先确认的是示例 URL 中的异常空格,以及 payInterceptorWithUrl 收到的字符串是否与 WebView 原始请求逐字节一致。确认这两项没有问题后,再继续检查支付宝客户端版本、SDK 兼容性和商户侧配置。
备注:内容仅供参考。
