首页 / 资讯中心 / 文章详情

微信H5支付调不起?从mweb_url到weixin://协议全链路排查指南

微信H5支付调不起?从mweb_url到weixin://协议全链路排查指南 ★ FEATURED ARTICLE
微信H5支付这东西我帮客户排查过不少次“拿到了 weixin://wap/pay?prepayid 却拉不起微信客户端”的问题。现象很统一订单页能正常下单后端也返回了一段以 weixin://wap/pay?prepayid 开头的地址前端把这段地址塞进 location.href 后iOS Safari 要么弹“无法打开网页”要么直接没反应Android 上倒是偶尔能把微信拉起来结果又提示“支付验证签名失败”。这篇文章就把这类问题从链路到排查、从参数到环境完整梳理一遍适合正在被微信H5支付调起折磨、或者马上要接手支付联调的同学照着抄。需要先说明一点我这里的排查思路以后端返回mweb_url、前端跳转到mweb_url再由微信服务器 302 到weixin://wap/pay?prepayid的标准H5支付流程为准。如果你是自己拼的 weixin 链接那大概率问题就出在拼链接这一步后面的内容会详细展开。1. 先搞清楚H5支付的完整链路才能定位问题出在哪一环1.1 从发起下单到拉起微信客户端中间发生了什么H5支付解决的场景是“用户在微信之外的浏览器里打开网页想用微信付款”。比如用户收到一条短信里面有一个商品链接点开后在手机浏览器里完成下单最后在支付方式里选微信支付。这个场景下前端点击支付按钮后会先请求后端下单接口后端拿着商户号、密钥、订单号、用户IP等参数去调微信支付统一下单接口微信支付服务端返回一个mweb_url形如https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_idwx1234567890abcdefpackagexxxx后端把这个mweb_url原样返回给前端前端跳转到这个地址。然后浏览器会访问腾讯支付服务器再由腾讯支付服务器根据当前浏览器环境和手机系统302到一个weixin://wap/pay?prepayidxxx的地址这一步才把控制权真正交给微信客户端。很多人看到weixin://wap/pay?prepayid就觉得这是一个可以拿来直接用跳转链接于是从mweb_url里把 prepayid 抠出来或者让后端只返回 prepayid前端自己拼一个 weixin 协议链接。这是整个排查链路上最常见、也最容易踩的坑。1.2 这个URL属于URL Scheme不是网页链接能不能拉起取决于系统注册与用户手势weixin://不是一个 HTTP 网页而是一个 URL Scheme是微信客户端在安装时向操作系统注册的协议。浏览器遇到这类协议会去问系统“谁能处理”系统找到微信就会拉起微信找不到就会提示用户“无法打开网页”或者干脆没反应。所以使用它有三个隐含前提手机装了微信、微信版本没有老到不支持该协议、跳转动作发生在用户主动点击的手势里。第三个前提很多人会忽略iOS 尤其严格如果在异步回调里执行 location.href浏览器可能直接吞掉这次跳转你看着代码确实执行了但页面就是纹丝不动。这里还要区分一个常见误区如果是微信内置浏览器里打开的网页那应该走的是公众号支付/JSAPI支付而不是H5支付。H5支付的服务对象是“微信外部浏览器”在微信内打开 H5 支付链接反而可能被拦截后面我会专门讲。2. 排查这五个最常见原因从高频到低频排2.1 最容易被坑的自己拼 weixin 链接而不是用官方 mweb_url我接手过好几个项目后端返回的数据结构是{prepayid: wx..., payParams: {...}}前端为了省事自己拼了个weixin://wap/pay?prepayidwx...然后跳转。这种做法的失败率极高。原因很简单weixin://wap/pay?prepayid后面携带的并不只是单纯一个 prepayid还需要package、noncestr、timestamp、sign等参数这些参数参与签名计算微信客户端拉起后会做本地验签。你自己拼一个只有 prepayid 的链接缺了签名参数微信客户端就算被拉起来也会很快提示“支付验证签名失败”。正确姿势是后端把微信统一下单接口返回的mweb_url原样返回给前端前端直接location.href mweb_url。剩下的事情交给腾讯支付服务器由它走完 302 跳转拼出合法的weixin://wap/pay?prepayidxxx。千万不要自己去解析 mweb_url、自己去拼 weixin 协议。2.2 跳转动作是否由用户点击触发决定了一半的“调不起来”即使你用的是官方mweb_url如果前端在页面加载后立刻自动跳转或者在fetch回调里延迟跳转iOS Safari 很容易拦截Android 部分浏览器的策略也不一样。我实际排查过一个项目支付按钮点击后先发请求去后端拿 mweb_url等接口返回后再执行location.href。iOS 大概 20% 概率拉不起来Android 上更高尤其某些国产浏览器几乎一半概率没反应。原因就是点击事件里发起了异步请求等回调执行时用户手势已经被浏览器判定为“非用户主动触发的跳转”。一个比较稳的改法页面加载时就请求后端预下单把 mweb_url 先存好用户点击支付按钮时直接location.href mwebUrl。如果必须点击后才调下单接口那就在拿到链接后不要立刻自动跳而是展示一个“确认支付”按钮让用户再点一次把跳转动作放到第二次点击的同步事件里。虽然多一步但成功率接近 100%。2.3 页面所在环境到底是不是“浏览器”这一步要分清weixin://协议不是所有环境都能被系统正确路由。最典型的是 App 内嵌 WebViewiOS 的WKWebView默认遇到 weixin:// 会报unsupported URL因为 App 没有实现对应的 navigation delegate 去处理自定义 schemeAndroid 的WebView需要 App 侧拦截 URL 并启动 Intent 才能调起微信如果原生层没写这段逻辑点击就是没反应。很多人以为“页面能在手机浏览器里打开就万事大吉”但如果这个页面是被 App 里的 WebView 加载的那就不一定能跳转微信。这时候要判断产品需求到底是不是真要在 App 内使用微信H5支付如果是原生端必须要处理 scheme 跳转或者换成拉起微信支付原生 SDK 的支付方式。另一个容易混淆的场景是“微信内打开网页”公众号菜单、微信扫码、微信里点链接这些都在微信内置浏览器里。此时走 H5 支付本身就不符合产品定义应该用 JSAPI/公众号支付通过WeixinJSBridge.invoke(getBrandWCPayRequest, ...)来调起。如果你非要在微信内置浏览器里跳mweb_url微信会判断环境并给出提示甚至直接拦截。2.4 商户后台的H5支付域名与下单参数是否配对微信支付 H5 支付在商户平台需要配置“H5支付域名”下单接口里还需要带上scene_info中的h5_info。如果这两处没有配对哪怕统一下单接口返回了 mweb_url跳转时也可能被微信支付服务器拦下来。商户平台的配置路径一般是微信支付商户平台 → 产品中心 → H5支付 → 开发配置 → 添加域名。这里注意填域名的时候不要加http://或https://也不要带路径比如只填example.com不要填example.com/pay。下单接口这里的参数大致是这样{ scene_info: { h5_info: { type: Wap, wap_url: https://example.com/pay, wap_name: 示例商城 } } }wap_url里的域名必须和商户后台配置的 H5 支付域名、实际浏览器的地址栏域名保持一致。如果其中一个地方填了测试域名、另一个填了线上域名跳转时就容易报“当前页面不允许支付”或“支付链接不合法”。2.5 别忽视版本、风控与缓存这几个背锅侠还有一些低频但很烦的情况微信客户端版本过老对新版 scheme 或 Universal Link 支持不完整同一台手机、同一个微信号短时间内反复测试支付触发风控微信客户端提示“当前交易有风险请稍后再试”prepay_id过期或被重复使用一般有效期是 2 小时而且一个支付链接用于一次支付后基本就不能再用了H5 支付链接在 PC 浏览器里打开也不会正常流转它只能在移动端浏览器里工作。这些情况排查起来不难。换一台真机、换一个微信号、等半小时再测就能过滤掉相当一部分环境因素。不要一看到报错就去改代码先确认是不是风控和缓存导致的。3. 从拿到 mweb_url 到拉起微信客户端的完整实操排查3.1 先用 curl 确认后端返回的链接和跳转目标拿到后端返回的 mweb_url 后先在 PC 上用 curl 确认这个链接是否正常。下面两条命令都行curl -I https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_idxxxpackagexxx或更完整地看状态码和跳转地址curl -s -o /dev/null -w %{http_code} %{redirect_url}\n https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_idxxxpackagexxx正常情况下返回的redirect_url应该以weixin://wap/pay?prepayidxxx开头。如果redirect_url不是这个说明问题大概率在下单参数或 H5 域名配置如果返回的是错误页可能是参数被二次编码、prepay_id 过期或者当前 IP 不在支付环境允许范围内。这里有个小经验curl 在 PC 上能拿到 302 跳转目标但很多项目在 PC 上继续访问这个 weixin:// 链接会“无法打开网页”这是正常的因为 PC 上没有安装微信客户端或者系统把 weixin 协议交给了某个不支持的程序。不要因为在 PC 上打不开就判定链接有问题关键看跳转目标对不对。3.2 在手机浏览器里手动输入链接排除前端代码问题用 iPhone 的 Safari 和一台 Android 手机分别手动打开 mweb_url 链接观察是否能正常拉起微信客户端。这一步能快速区分“链接本身问题”和“前端跳转代码问题”。如果手动打开也没反应去检查手机是否装有微信、微信版本是否过旧、系统里有没有其他 App 抢占了weixin://协议。Android 尤其容易出现其他软件注册了类似 scheme 的情况。如果手动打开正常但自己的页面跳不过去问题就在前端代码。重点看跳转是否在用户手势同步执行栈里有没有用window.open导致被弹窗拦截有没有在 setTimeout 或 fetch 回调里跳转。3.3 用 vConsole 和真机调试抓跳转时的真实状态移动端调试不方便开 DevTools可以在页面里引入 vConsole然后在支付按钮的点击事件里打印关键信息// 点击支付按钮 function onPayClick(payUrl) { console.log([支付] 当前时间, new Date().toISOString()); console.log([支付] 当前页面, location.href); console.log([支付] UA, navigator.userAgent); console.log([支付] 即将跳转, payUrl); // 同步跳转 location.href payUrl; }打印出来之后把手机浏览器和微信客户端的表现对照一下日志里根本没有这条输出说明按钮点击事件没绑上或者事件在更早的地方被阻止了。日志有“即将跳转”但页面停在原地说明浏览器拦截了这次跳转重点检查异步回调问题。日志有“即将跳转”页面也跳到了空白页但微信没被拉起说明是 scheme 或系统注册的问题。iPhone 还可以用 Mac 上的 Safari“开发”菜单直接连接真机看 consoleAndroid 可以走 Chrome 的 remote debugging但如果现场没条件vConsole 是最省事的方案。3.4 服务端核对下单参数与返回字段如果前端一切正常还是要回头核对服务端下单的入参。微信H5支付统一下单时至少要确认appid、mch_id、随机字符串、签名方式是否正确订单金额、订单描述、回调通知地址是否合法spbill_create_ip是否为用户真实外网 IPscene_info里的h5_info是否包含正确的typeWap、wap_url、wap_name微信返回的mweb_url有没有被服务端做 urldecode、去参、加参数等操作。有任何一个不对统一下单接口可能仍然返回 prepayid 和 mweb_url但后续跳转时会出问题。尤其一些开发同学在测试环境里用内网 IP 或127.0.0.1下单微信服务端拿不到合理的来源调起这一步就会卡住。我遇到过一个项目服务端把 mweb_url 里的转成amp;存数据库前端又用innerHTML渲染成一个a链接用户点击以后浏览器地址栏看到的 URL 长得正常实际上里面全是 HTML 实体微信当然不认。这种问题从头到尾都是“传递过程中被篡改”造成的。4. 常见报错与调起失败现象速查表下面这张表是我在排障过程中积累的高频问题对照基本覆盖了“拿到了 prepayid 却调不起来”的大多数情况。可以收藏起来下次遇到问题先对号入座。现象大概率原因处理建议Safari 提示“无法打开网页”weixin:// 没有被系统处理或微信版本过旧跳转发生在异步回调里升级微信用用户主动点击同步触发使用官方 mweb_url 跳转Android 点击后直接没反应页面在 App 内嵌 WebView 中原生没有处理 weixin scheme或浏览器没有关联微信换系统浏览器测试App 内 WebView 需要原生配合拦截 scheme 并拉起 Intent微信被拉起但提示“支付验证签名失败”手拼 weixin:// 链接缺少正确签名参数停止自己拼链接改用统一下单返回的 mweb_url提示“当前页面不允许支付”H5 支付域名没配好或实际页面域名与配置不一致核对商户平台 H5 支付域名、scene_info.wap_url、浏览器地址栏域名三者一致提示“订单已支付/链接失效”prepay_id 重复使用、过期或订单状态异常重新下单生成新 mweb_url 再去支付检查回调通知不能重复更新订单状态提示“今日无法继续交易/当前交易有风险”触发风控通常因为同一微信号/手机短时间多次测试更换微信号或手机间隔一段时间再测正式环境避免反复用同一账号试单补充一句微信不同版本、不同机型上提示文案可能不一样但底层原因基本逃不出这几类。不要一看到报错就改代码先拿一条新的 mweb_url 在原生浏览器里手动验一下。5. 文档里不会写但实测很有用的几个细节5.1 拿到 mweb_url 后尽量“原样透传”别自作聪明解码后端收到微信返回的mweb_url后最忌讳的就是做 urldecode、再拼接、再加参数。这个链接里包含了很多微信服务端生成好的签名和标识位任何改动都可能让跳转失效。前端也一样。不要把 mweb_url 经过模板块转义、HTML实体处理、或者拼接成“带尾巴”的地址。我曾经花了两小时排查一个“用户在 Android Chrome 可以支付在 iOS Safari 就是打不开”的问题最后发现是前端在 mweb_url 后面又拼了一个?fromh5参数iOS 对 URL 参数解析更严格微信验签直接失败。原则只有八个字原样透传不要自作主张。5.2 用a标签而不是 window.openH5支付跳转推荐用location.href或window.location.replace不要用window.open。iOS Safari 对window.open的拦截非常严格尤其是异步流程里弹出的新窗口大概率被当作弹窗广告直接关掉。如果想做得更稳可以在支付按钮点击时预先设置一个a标签的 hrefa hrefhttps://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_idxxx classpay-link立即支付/a用户点击原生链接浏览器和微信之间的交互由系统处理基本不会遇到“非用户手势跳转被拦截”的问题。缺点是页面会直接跳走如果还要保留订单状态需要先在前端保存订单号等用户从微信返回后通过订单号恢复页面。5.3 测试要准备真机并且把微信升级到最新H5支付在模拟器、浏览器开发者工具的设备模拟里几乎没法完整走通因为微信客户端的 scheme 注册、Universal Link 支持都依赖真实系统环境。最稳妥的是准备一台 iPhone 和一台 Android 真机安装最新版微信。测试支付时还有一个容易忽略的点不要用商户后台管理员或商户联系人常用的微信号来反复测试小额支付不然很容易触发风控。我习惯准备两三个不同的微信号轮流测试遇到风控提示就换号从而把“交易有风险”这类环境原因快速排除掉。5.4 判断是不是微信内部浏览器环境微信内部浏览器和普通手机浏览器对 H5 支付的处理完全不同。区分方法很简单看 UA 里是否包含MicroMessengerconst ua navigator.userAgent.toLowerCase(); const isWechat ua.indexOf(micromessenger) ! -1;如果isWechat为 true页面在微信内置浏览器里就不应该走 H5 支付应该走 JSAPI/公众号支付。如果业务上必须兼容“微信内打开”和“外部浏览器打开”两种场景建议按 UA 分支分别处理微信内调 JSAPI外部浏览器调 H5。不要试图在微信内打开 H5 支付链接再引导用户“复制链接到浏览器打开”这种体验不仅差而且微信那边本来就不推荐接口约束也越来越严格。6. 从一次真实排障看完整思路最后再分享一个实际案例。之前有个客户反馈安卓手机在微信公众号菜单里点支付能正常拉起微信但在手机自带的浏览器里打开同样一个页面点击支付按钮后页面白一下微信就是不出来。我远程指导他们按下面顺序排查第一步后端把统一下单返回的 mweb_url 打印出来手动在安卓浏览器里打开发现能正常拉起微信说明 mweb_url 本身没问题。第二步在前端打印跳转日志发现点击按钮后代码先走了一个fetch请求成功回调里才执行location.href。第三步把跳转改成预下单拿到链接后用户再点一次“确认支付”问题就消失了。还有一个类似的案例现象是 iOS 能支付安卓不能。排查后发现问题出在 App 内嵌 WebViewAndroid 的 WebView 没有拦截 weixin:// 协议也没有启动微信 Intent所以点击支付按钮以后页面会尝试跳转但没有任何 App 响应。iOS 的 WKWebView 虽然会弹“无法打开”提示但至少能看出是 scheme 问题。这类场景不是前端改改代码就能解决的必须让原生开发介入在 WebView 导航拦截里处理weixin://或者干脆使用原生微信支付 SDK。我个人的习惯是遇到调不起微信客户端的报障先不动代码先让现场把支付链接单独发出来我用 curl 看一眼跳转目标再用真机手动打开一次。这两步做完至少能排除掉一半的原因。剩下的一半基本都是“自己拼链接”和“异步回调跳转”这两个老问题。做微信H5支付最忌一遇到问题就去翻代码、改参数。整条链路上从下单参数、mweb_url 透传、前端跳转时机、到系统环境和微信版本每一环都可能出问题。先把“用官方 mweb_url、同步跳转、原样透传、核对域名”这十六个字记牢然后按我上面给的排查顺序一步步来大多数调不起来的问题都能快速定位。
阅读完成 · 觉得有帮助?
咨询建站