0 描述
本文所说的微信公众号支付连接,是指对接第三方支付平台的微信公众号支付接口,并不是微信支付官方文档中类似公众号支付开发者文档的连接。不过腾讯毕竟会把一些通道让给有支付牌照的银行或者支付机构,所以第三方公众号支付也是基于腾讯微信公众号支付的改造,所以基本的请求参数、签名机制、响应参数、交互流程、数据格式都是一样的。
1 简介
.....
2. 解决方案概述
2.1 行业背景
微信支付是微信客户端提供的支付服务功能,同时为商户提供销售及运营分析、账户及资金管理等功能,用户可以通过扫描二维码、反扫二维码等方式调用微信支付模块完成支付。
【二维码支付正扫与反扫有什么区别】
扫一扫:二维码支付,即商家提供支付二维码,消费者用手机APP扫码支付
反向扫描:支付码支付,即消费者提供支付二维码,商户使用扫描器扫码收款
2.1.1 公众号支付
公众号支付就是用户在微信中打开商户的H5页面,商户通过调用微信支付提供的接口,在H5页面调用微信支付模块完成支付。应用场景包括:
◆ 用户在微信公众号进入商户公众号,打开主页面,完成支付
◆ 用户的好友在朋友圈、聊天窗口等分享商家页面链接,用户点击链接打开商家页面并完成支付
◆ 将商户页面转化为二维码,用户扫描二维码后在微信浏览器打开页面并完成支付。
【两种实现方式】:原生js支付、封装
2.2 业务实施流程
2.2.1 对公账户支付服务
微信网页支付顺序图
从图中可以看出,商户系统涉及的交互操作有:
1. 生成短信链接或二维码
4.生成商户订单
5.调用统一订单API------------------------
6.生成页面调用支付参数并签名
10.异步通知商户结果-----------------------
13.查询后台支付结果
14.调用查询API查询支付结果--------------
3 数据格式
xml
4 数字签名
4.2 签名算法
MD5 签名
MD5是一种摘要生成算法,通过将商户的通信密钥添加到原始签名字符串中,并进行MD5运算,得到的摘要字符串即为签名结果。
4.2.1 随机数生成算法
微信支付API接口协议中包含字段,主要用来保证签名的不可预测性,我们推荐使用如下算法生成随机数:调用随机数函数生成,并将得到的值转化为字符串。
5.订单补货机制
通知重试机制
6 公众账号支付接口
6.1 初始化请求接口
6.1.1 业务功能
通过生成请求来初始化执行交互式验证的请求。
几个特殊的请求字段
字段名称
变量名
必需的
类型
阐明
是正品吗?
√
(1)
是正品吗?
用户
(128)
关注商家公众号的微信用户(注:
使用测试商户账户时无需转移用户;
切换官方商户号需要获取,并将获取到的值传给它,切换官方商户号和传递参数前需要提供渠道方配置的官方商户号和公众号(服务号),若不配置会报and not错误,导致无法正常调用接口)---------下面文章会介绍如何获取
前台地址
(255)
交易完成后跳转的URL,必须是255个字符以内的绝对路径,格式如下:注意:此地址只作为跳转前端页面,必须以通知结果作为最终支付结果。---------扫码支付无此参数,即商户不需要发送交易完成的h5页面,公众号支付此参数可选,商户也可以发送此页面做一些营销活动
信用卡有限制吗?
(32)
限制用户使用微信支付时是否可以使用信用卡,值为1表示禁用信用卡;值为0或者不传递参数表示不禁用信用卡。默认支持信用卡,因此此字段可以省略。微信个人转账不支持信用卡支付,这是和公众号支付、扫码支付最大的区别。
6.1.2 交互模式
:后台请求交互方式
返回结果+通知:后台请求交互方式+后台通知交互方式
注意:一般来说,失败的结果没有标志。
是否原版?否(1)值为1:是(对应文件第6.2节);
值为0:否(对应文档6.3章节);若不传递则默认为0
6.2 原生js支付接口 ---------------------- 原生js支付示例:可以关注“1号外卖”公众号或者直接在手机上微信里钱包里查看手机充值
6.3 公众账号JS支付接口------------这就是所谓的“封装形式”(H5网页支付模式)
6.3.1 业务功能
通过生成请求来初始化执行交互式验证的请求。
如果调用时使用原有js支付,可忽略此接口
6.4 JS支付通知接口
同《威富通扫码支付接口文档V1.4.2.pdf》 6.2 扫码通知接口
——————【重要】必读第一篇.txt————————————————————————————————————————————————
1.开发的时候可以先使用测试商户号和key(demo里也写了)
测试
商业编号:''
钥匙: ''
2、测试商户账户支付限额为1元,正式商户账户无此限制。
3.文档中请求接口时传递的参数为必填项,必须传递(缺失会报错),非必填项可传可不传。
4、必填项填写yes的参数一定会返回,必填项填写no的参数可能不会返回,以实际收到的参数为准。
5.注意文档提供了两种实现方式,PHP和C#版本的demo实现了我们封装好的表单,调用支付请求接口获取,然后组装成这样的链接去调用服务号里的支付(用户在页面点击微信支付按钮的时候,其实就是点击了这个链接)。JAVA版本实现了原生js支付和封装好的表单,在原生支付的时候,调用支付请求接口获取,带上参数去调用微信(这种方式和微信最终调用时官方原生接口一致)
包装形式直接点击链接即可,很简单,比如可以关注“广州城市站”公众号查看详情。
原生js支付示例:可以关注公众号“1号外卖”或者直接在手机上查看微信钱包里的手机充值
6.demo中测试商户号不需要传递给用户,即该参数留空
但切换官方商户时必须传入接口请求参数,同时请提供官方商户号和公众号(服务号)以供我们配置,若不配置则会报and not错误,导致无法正常调用接口。
获取指导文档地址:
获取公众号指导文档地址:
——————公众号支付两种实现模式说明————————————————————————————————————————————
公众号支付流程是先调用接口文档6.1节初始化请求接口,获取对应的返回值和(对应值是json格式的字符串,=1时才返回),返回参数为下图所示的XML格式:
然后接下来就分为两种不同的模式:6.2节原生JS支付和6.3节公众账号JS支付
6.2 原生JS支付
调用微信方法,该方法只能在微信内置浏览器调用,其他浏览器无效,示例如下(注意:示例代码中的六个参数区分大小写,对应值为初始化请求接口中返回的参数值):
function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest',{ "appId" : "wx1f87d44db95cba7a", //公众号名称,由商户传入 "timeStamp": "1468591622013", //时间戳,自1970 年以来的秒数 "nonceStr" : "1468591622013", //随机串 "package" : "prepay_id=wx201607152207013ae4e376760784153308", "signType" : "MD5", //微信签名方式: "paySign" : "AD5A9E19D38002461812E09C0910A815" //微信签名, },function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { // 此处可以使用此方式判断前端返回,微信团队郑重提示:res.err_msg 将在用户支付成功后返回ok,但并不保证它绝对可靠,。 document.location.href="pay_success.jsp"; } /* for(var i in res){ alert(res[i]); } */ } ); }
最后在网页代码中调用这个js方法就可以调用微信支付了,例如:
微信支付
但若想正常弹出支付密码框,商户开发者必须自己提供由服务商配置的支付授权目录,支付授权目录即方法代码所在页面的文件路径,如授权目录(若不配置授权目录,支付时将不会弹出密码框或提示当前页面网址未注册)
6.3 公众账号JS支付
该模式是我们自己封装的,利用6.1节初始化请求接口获取到的值,组装出这样一个链接来调用手机微信支付(用户在页面点击微信支付按钮时,其实是点击了这个链接,你可以把链接放到手机微信文件传输助手里点击测试一下,注意值一定要改成有效的)。该模式不需要实现方法,也不提供支付授权目录。
对比6.2节中的原生JS支付,直接点击链接,在弹出支付确认弹框的时候,会出现一个上面是绿色,下面是白色背景的页面。其实这个背景页面就是我们封装好的支付授权目录页面(对应固定授权目录),这也是为什么商户不需要提供支付授权目录的原因。
效果如下图:
总体来说,封装好的链接格式开发起来更简单,商户也不需要自己提供授权目录(我们固定配置),但是体验可能不如原生js支付。
参考:
微信支付开发文档
微信支付公众号支付开发文档
微信公众号支付H5调用详解(附代码)
——————获取微信用户信息————————————————————————————————————————
关于用户:关注者与公众号进行消息互动后,公众号可以获得关注者的(加密微信号,每个公众号每个用户唯一,不同公众号相同用户的微信号不同)。
此次获取属于微信公众平台开发范围,请参考以下地址:第3节《通过.0方法不弹出授权页获取用户基本信息》
:配置回调域名
登录微信公众平台,菜单“设置”→“公众号设置”→功能设置→Web授权域名
【定义】授权回调页域名:用户在网页授权页同意授权公众号后,微信会把授权数据传给回调页面,回调页面必须在这个域名下,以确保安全可靠。
上面的定义好像会让人产生误解,我一开始也搞不清楚,我配置了回调地址,但是没必要,只需要配置授权访问的域名就可以了,这里我就配置好了,注意域名一定要可以访问,并且****.txt一定要放在站点对应目录下,否则点击“确认”按钮的时候会提示。
:构造微信用户访问的URL:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb8239ab824d12860&redirect_uri=http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx&response_type=code&scope=snsapi_base&state=1#wechat_redirect
页面URL中的=表示应用授权范围为直接跳转,不弹出授权页面。
这时候我们就可以获取到所指向的页面”程序中的get方法的两个参数值code和。
:根据代码:
请求 URL:
返回值:{"":"k2iC--","":7200,"":"--","":"","":""}
注意,一般情况下,当code不合法时,返回值为{"":,"":" code, : [ : 1. ]"}
程序代码如下:
public partial class WeixinJSPay : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { tbOpenId.Text = GetOpenIdByCode(); } /// /// 微信用户访问时,获取其openid /// private string GetOpenIdByCode() { /* * 给微信用户的请求地址: https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxb8239ab824d12860&redirect_uri=http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx&response_type=code&scope=snsapi_base&state=1#wechat_redirect */ LogHelper.Write("--------:" + Request.Url);//示例:http://testpcenter.shenbianhui.cn/QRCodeDemo/WeixinJSPay.aspx?code=001bxIJx1Pi1ge0bZpLx1AAAJx1bxIJb&state=1 string code = Request["code"]; if (string.IsNullOrEmpty(code)) return "未获取到code参数"; string url = string.Format( "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", "wxb8239ab824d12860", "0e8d4313fd5345da5ea8e5fab61ddae7", code); LogHelper.Write("--------请求openid:" + url); string resultJson = CommonModel.WebCommon.SendStreamStr("", url); LogHelper.Write("--------响应报文:" + resultJson); dynamic model = JsonConvert.DeserializeObject<dynamic>(resultJson); if (model.openid == null) return "未获取到openid"; return model.openid; } }