关于一个二维码实现微信支付宝同时付款的全部技术内容,包含官方文档索引

955 阅读6分钟

一个二维码,同时实现支付宝和微信付款,这感觉是一个不难实现的功能,就像很多文章写的,只需要判断user-agent信息就可以了,但实践下来,发现这只是走了1%的路,后面的坑主要集中在两个平台的API上,以下就是个人一条路走下来技术内容的总结。

此文写于2020年初,后端使用PHP,个人非职业程序员,仅供参考。

基本条件

微信:公众号开通微信支付
支付宝:建立一个Web应用

这里的细节与技术无关,不多叙述,不过有几个点:

  • 微信公众号和支付宝web应用设置中的回调地址一定要设置好,否则无法下单。
  • 下单这一步可以使用微信开发者工具调试,支付宝的开发工具似乎不能调试Web应用。
  • 用户付款貌似只能在手机上调试。
  • 微信支付的货币单位为__分__(不同接口亦有不同),支付宝的货币单位为__元__,注意转换

使用的API

首先,最重要的,两个平台都有不同的支付产品,要实现一码多付的功能需要开通的API是:

微信:JSAPI支付

只能对公账户,开通微信支付需要进行公众号认证,300元一年。费率0.6%(非信用卡)

支付宝:当面付

可以对公亦可以对私,无其他费用。费率0.6%(非信用卡)

基本流程

这并不是一般的扫码支付情况,因为展示的二维码指向的是自己的地址,而不是微信/支付宝的付款二维码。所以应该是用微信/支付宝客户端打开对应页面后,页面通过对应的Js Bridge调起支付流程。支付宝把接口放在· 当面付 ·里,逻辑上有点不太对。

虽然用的支付产品名称完全不同,不过两家的流程是一模一样的,所以业务逻辑可以尽量统一。以下是一路成功的流程,其他情况自行补全。

  • [前端] 用户扫码
  • [后端] 获得用户的Open ID(微信)/User ID(支付宝)
  • [前端] 用户在客户端输入金额/核对金额
  • [前端] 客户点击支付按钮
  • [后端] 向微信/支付宝服务器下单
  • [后端] 将微信/支付宝返回的下单信息返回到前段
  • [前端] 调起客户端的支付界面
  • [前端] 用户支付
  • [前端] 向后端查询支付是否成功
  • [后端] 接收平台通知/主动向平台查询
  • [前端] 显示支付成功信息

获得用户的Open ID(微信)/User ID(支付宝)

因为后面的下单需要用户的Open ID/User ID,所以在用户扫码这一步就要完成获取。

对应文档:

微信

微信SDK提供GetOpenid可以直接获得用户的OpenID

支付宝

支付宝需要先自行获得auth_code,再使用接口获得User ID

//拼接当前URL并进行Url Encode
$baseUrl = urlencode(
“https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]”);
//拼接请求URL
$url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=$alipay_app_id&scope=auth_base&redirect_uri=$baseUrl";
//重定向
Header("Location: $url");

//返回的请求通过GET参数传递auth_code,需自行判读是否返回了auth_code再执行以上操作

获得了auth_code就可以通过Alipay.System.Oauth.Token接口换取User ID了。可以详见支付宝对应文档。(支付宝授权的借口有好几个,亲自试过,只有这个可以用)

成功获得了用户的OpenID/UserID后,可以存储在Session中,当然也可以由前端再返回。

向微信/支付宝服务器下单

这是最核心的一步,不过却最容易实现,因为两方SDK都提供了完善的接口。需要注意微信以分为单位,支付宝以元为单位。

微信接口:统一下单,获得一串jsapi支付参数

支付宝接口:Alipay.Trade.Ctreate,获得一个Trade NO.

调起客户端的支付界面

使用后端获得的交易参数,就可以在前端(微信/支付宝客户端内)发起支付流程,以下代码主要来自官方SDK,略微整合,使用callWxPay()callAlipay()可以分别在网页中调起微信支付和支付宝支付。

var jsApiParameters = '微信JSAPI支付参数';
var alipay_trade_no = '支付宝交易号';

function callWxPay() {
    if (typeof WeixinJSBridge == "undefined") {
        if (document.addEventListener) {
            document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
        } else if (document.attachEvent) {
            document.attachEvent('WeixinJSBridgeReady', jsApiCall);
            document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
        }
    } else {
        jsApiCall();
    }
}
//调用微信JS api 支付
function jsApiCall() {
    WeixinJSBridge.invoke(
        'getBrandWCPayRequest',
        jsApiParameters,
        function (res) {
            if (res.err_msg == 'get_brand_wcpay_request:ok') {
                //微信客户端返回支付成功
            } else {
                
            };
        }
    );
}
//微信模块结束--//
//--支付宝模块开始--//
function callAlipay() {
    if (window.AlipayJSBridge) {
        AlipayTradePay();
    } else {
        document.addEventListener('AlipayJSBridgeReady', AlipayTradePay, false);
    }
}

function AlipayTradePay() {
    // 通过传入交易号唤起快捷调用方式(注意tradeNO大小写严格)
    AlipayJSBridge.call("tradePay", {
        tradeNO: alipay_trade_no
    }, function (data) {
        if ("9000" == data.resultCode) {
            //支付宝客户端返回成功
        } else {
            
        };
    });
}
//--支付宝模块结束--//

向后端查询支付是否成功

用户确认支付后,微信和支付宝客户端都会返回支付成功,然而完全依赖前端信息并不安全,要有一个查询是否支付成功的机制, 所以当客户端返回支付成功后,就要开始向后台轮询支付状态

接收平台通知/主动向平台查询

接收支付通知

关于接收支付状态通知,微信文档写的比较明白,SDK也都有,这里不再不详述,不过支付宝的通知由于其文档提到“异步通知仅用于扫码支付”,尝试了一次确实也没有收到通知,所以没有做进一步的尝试,只能依赖向服务器查询订单支付状态了。

主动查询接口

微信:https://api.mch.weixin.qq.com/pay/orderquery

支付宝:Alipay.Trade.Query

官方参考文档链接

微信

微信文档虽然也有很多坑,不过相对清晰,不一一列举

pay.weixin.qq.com/wiki/doc/ap…

支付宝

支付宝的文档不好找,看了好几天只能求助客服,技术客服参差不齐,有些完全不听你说什么,像机器人一样回答问题,估计跟“支付宝小二”这个没有专业性的职位称呼有关,不过最终还是遇到明白的客服,一下给出下面这篇不在目录之内却极具针对性的文档(虽然我是动态码),基本上只看这篇就够了

线下静态码支付方案 alipay.open.taobao.com/docs/doc.ht…

PC 网页内获取用户信息 docs.open.alipay.com/284/web/

换取授权访问令牌 docs.open.alipay.com/api_9/alipa…

统一收单交易创建接口 docs.open.alipay.com/api_1/alipa…

JSAPI唤起收银台支付 docs.open.alipay.com/common/1055…