微信H5支付之回跳 safari 浏览器
2017-12-04 09:00:13 # fontend

最近,公司发布一款新产品,需要在 iOS App 上集成微信 H5 支付(嗯,我知道微信官方建议我们不要在APP环境下使用H5支付)。用到的关键步骤如下,参考文档微信支付-H5支付

  • 由我们后台向微信支付发起统一下单请求
  • 统一下单接口返回支付相关参数给商户后台,拼接成支付跳转url,商户通过此 url 去访问微信支付中间页
  • 中间页会生成一个“weixin://wap/pay?” + 参数 这样一个scheme去调起微信客户端走到下单页面。

补充说明:

跳转url(mweb_url)示例: "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx201711302016180757ed93760351075895&package=2940730744"
scheme 示例: "weixin://wap/pay?prepayid%3Dwx201711302016180757ed93760351075895&package=2940730744&noncestr=1512044179&sign=df7fb3081e1eec19e5e3640ea97d31c3"

那么问题来了

再次声明,此处所说的问题在H5环境下并不是问题。我们讨论的是iOS上的App环境下使用微信H5支付的跳转问题

唯品会 为例:在非 safari 浏览器下(比如 chrome 浏览器)打开唯品会 M站,走到提交微信支付订单,网页调起微信支付,尽管你设置了 redirect_url(回跳地址)并且关闭 safari,但是取消支付或者支付完成之后微信还是会跳回 safari 浏览器打开你的回调页面,而不是跳转至 chrome。这个时候就尴尬了,你得自己切换回到 chrome。如果我是用户,我至少会有点懵逼。

手机京东 为例:操作步骤同上,但是取消支付或者完成支付之后,不会跳回 safari,而是关闭支付页面,继续留在微信。虽然没有直接回到 chrome,但是这总比突然去打开 safari 更让人容易接受。

以上情况属于:

  • 特殊的运行环境:iOS上的原生App或者非safari浏览器(UC浏览器也不会跳回safari)
  • 指定的支付环境:微信H5支付
  • 奇怪的回跳逻辑:有的会打开safari,而有的并不会

我们的期望肯定是能回跳到发起微信支付的 App 是最好的,不过在这之前需要先弄清楚为什么会出现这样的回跳逻辑差异。

分析差异

支付流程

首先得分析两个M站的微信支付流程吧,上面提到过关键步骤就是:

普通的支付流程:后台发起统一下单请求 –> 微信支付接口返回给你相关参数 –> 根据参数去拼接一个 mweb_url 的地址,你需要做的就是 location.href = mweb_url –> 这个页面里会生成一个 微信 scheme 地址,调起微信客户端支付。这是普通商户的,也是唯品会的H5支付流程。

通过抓包得来的 mweb_url 地址页面的关键 js 内容如下,微信 scheme 会在这个页面自动生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<script type="text/javascript">
if (0 === 0) {
window.onload = function() {
{
var is_postmsg = "";
if (is_postmsg == "1") {
parent.postMessage(JSON.stringify({
action: "send_deeplink",
data: {
deeplink: "weixin://wap/pay?prepayid%3Dwx20171204195948d0d40803800224970868&package=121328958&noncestr=1512388788&sign=545a16c77fd27d98a3eaf23751ec6104"
}
}), "");
} else {
var url = "weixin://wap/pay?prepayid%3Dwx20171204195948d0d40803800224970868&package=121328958&noncestr=1512388788&sign=545a16c77fd27d98a3eaf23751ec6104";
var redirect_url = "https://npay.vip.com/wap/cashier/doPay?paySn=17120467932547060971&sid=D4D4043F87D714D61FDC13B1763BCA1FFF30491E&t=1512388788060&type=queryOrder&orderSns=17120467932547";
top.location.href = url;

if (redirect_url) {
setTimeout(
function() {
top.location.href = redirect_url;
},
5000
);
} else {
setTimeout(
function() {
window.history.back();
},
5000);
}
}
}
// );
}
}
</script>

不过,京东并不是这么做的。

京东的微信支付流程:进入下单页面选择微信支付 –> 前端发起 GET 请求后台 –> 京东后台直接返回了微信 scheme 地址,(是直接返回了,而不是通过访问拼接的mweb_url地址做跳转,这一步普通商户也可以做到,但是可能也还是有差异的) –> 根据此地址在当前支付页面 append 一个 A 标签,塞进此地址,自动触发点击事件 –> 调起微信支付,M站的支付页面经过5秒的延时会弹出一个mask弹窗来触发查询支付订单操作。

微信 scheme

唯品会的:

weixin://wap/pay?prepayid=wx20171204195948d0d40803800224970868&package=121328958&noncestr=1512388788&sign=545a16c77fd27d98a3eaf23751ec6104

手机京东的:

weixin://wap/pay?appid=wxae3e8056daea8727&noncestr=24bfde45b5790f04b1d096565157f6a4&package=WAP&prepayid=wx201712041702047d0d37c44f0850922294&timestamp=1512378124&sign=89BE2251D47BF1EEB48CA3C8D62A1967

京东多了 appid,timestamp 参数,并且京东的 package 参数指定为 WAP,这是通过多次抓包得到的验证,package是固定的并且目测所有不发生回跳safari的都固定为WAP。appid 是微信分配的公众账号 ID,这个值每个商户是都有的,所以我们想当然的就这样去模仿京东的微信 scheme,但是到了微信下单页面,我们看到了这个报错:

微信报错

分析结论

很显然这么做是行不通的,既然让你提供 appid 参数,肯定会做出相应验证。所以由此说明微信团队应该是有白名单的。

于是相继测试了许多大站的M站微信 H5 支付,目测 京东,美团,猫眼电影,大众点评,饿了么 都在白名单列。其他的类似唯品会,蘑菇街,聚美优品,一号店,去哪儿,途牛,携程都会回跳至 safari。

不算完美的解决办法

目前针对这种情况,我们是无能为力的,自己开发的 iOS App 如果走的是微信H5支付,比如 web app,只能通过在safari 打开的回跳地址中自行添加自己应用的 scheme 地址调起应用,看过大多数 web app 都是这么做的。

虽然折腾了这么多,去看各大站的微信 H5 支付流程,去抓包微信跳转的 mweb_url 地址和微信 scheme 地址做对比和测试,去改后台请求微信支付接口的参数等等,这些都行不通,但是至少弄明白原来微信H5支付还有这种操作,希望能为一些开发者解惑。