JS-SDK微信支付开发攻略
一、吐槽篇
一个字——坑!两个字——很坑!三个字——非常坑!首先,微信支付接口作为微信开发接口的一部分,竟然有一本书那么厚的官方文档,共36页,更重要的是,这36页还不能把开发的流程说清楚,描述过于分散,过度分类,导致遇到一个问题的时候很难定位,虽然文档前面给了时序图,但是开发流程的时序化仍然不够,让人觉得十分混乱。本来接手这个任务的时候时间就非常的紧,想着找个demo撑死一两天就完事了,没想到最终耗费了接近一个星期,除去中间别的事耽误的时间也用了整整五天的时间,在网上查找资料的时候也看到很多人说一个问题卡好几天甚至几周的情况,实在是难以接受。
二、开发流程
我这里就一并按顺序总结了。首先我用的是JS-SDK,即官方文档所描述的方式去做,必须说明的是,虽然是JS-SDK,但是整个签名过程不可能只在JS里完成,由于安全性问题,微信提供的接口JS是无法跨域调用的,必须在后台进行调用再将结果发给前台。OK,我的开发的宏观情况是,前端使用JS-SDK,后端使用JAVA tomcat。
总体流程是:①授权部分:后端通过微信接口拿到access_token,再拿到ticket(jsapi_ticket),给前台,前台通过js-sdk将jsapi_ticket,noncestr,timestamp,url签名,获取授权。
②支付部分:前端获取code,给后端,后端通过code访问微信接口拿到openid,通过openid等一堆key信息和回调url拿到prepayid,把prepayid,timestamp,noncestr给前台,前台通把这些东西以及签名提交,发起支付。
③回调部分:支付成功后,支付部分填写的url的对应方法会执行,拿到后从参数中拿到支付成功后的信息,校验签名,发送成功结果给支付发起端。
④完成部分:前端收到成功的消息,自定义跳转页面。
1、授权部分
js部分:
- wx.config({
- debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
- appId: '', // 必填,公众号的唯一标识
- timestamp: , // 必填,生成签名的时间戳
- nonceStr: '', // 必填,生成签名的随机串
- signature: '',// 必填,签名,见附录1
- jsApiList: ["chooseWXPay"] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
- });
- 这是发起授权申请的部分,signature需要签名的字段包括:
- "jsapi_ticket="+ticket+"&noncestr="+noncestr+"×tamp="+timestamp+"&url="+url;
- 说明:
- ①jsapi_ticket获取:
需要调用接口获取,调用接口不能用js(跨域),所以在后台进行,接口调用使用https://api.weixin.qq.com/cgi-bin/ticket/getticket,GET方法即可,参数是"access_token="+access_token +"&type=JSAPI"
②access_token获取:
调用https://api.weixin.qq.com/cgi-bin/token,同样使用GET方法,参数是"appid="+appid+"&secret="+secret+"&grant_type=client_credential",只要参数不错,就能拿到jsapi_ticket了。
(后面获取opendid的时候也会拿到一个access_token,但不是同一个!)
- ③nonceStr、timestamp在JS生成即可,记得签名时候的timestamp和nonceStr要和参数填写的一样。
④签名规则:
就是在上面那一串东西后面加上"&key=xxxx",然后MD5加密处理后,变成大写,key是商户的key,千万别搞错了,不是appkey。规则具体看这里。
⑤appId,这里I是大写的
⑥url的获取:
这个url不需要urlencode,但是必须是当前发起支付页的url,若url中有#号,只取#前面的。下面代码直接拿走吧!
- location.href.split("#")[0]
⑦invalid signature:如⑥所说,url输入的不对,url要动态获取
⑧invalid url domain :url和appid没绑定,要在微信公众号那里的功能配置里配置,别把安全域名和业务域名搞混了……(我就在这里卡了半天)
- 配置成功后,就会进入
- wx.ready(function(){
}
这个函数里面,并且如果debug打开,能看到configok的反馈。- 2、支付部分
为了确保wx.config成功后再支付(否则不可能支付),请把下面函数放到wx.ready里面:
- wx.chooseWXPay({
- timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
- nonceStr: '', // 支付签名随机串,不长于 32 位
- package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
- signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
- paySign: '', // 支付签名
- success: function (res) {
- // 支付成功后的回调函数
- }
- });
- 首先说明填写要怎么填,别的应该都好理解,package这个东西有点不明所以,这个东西官方文档叫做扩展包,但是在整个官方文档里却又找不到扩展包要填什么,只知道肯定要填"package=prepay_id=xxxx",我翻查了旧版微信支付的demo等,知道了这个扩展包主要是填写一些选填的东西,例如币种、编码等,但这并不是必须的,用最简单的"package=prepay_id=xxxx"填写就可以了。
- 先给出要签名的字符串列表
- String signstr = "appid="+appid+"&body="+body+"&mch_id="+mch_id+"&nonce_str="+nonce_str+"¬ify_url="+ notify_url +"&openid="+openid+"&out_trade_no="+out_trade_no+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&trade_type=JSAPI"+"&key="+appkey;
说明
①签名必须在后端完成,前端timestamp和nonceStr必须和后端签名时用的值一致。
②notify_url不需要urlencode,回调地址最好不要加参数(回调地址是支付成功后通知的那个地址接口,接口内容自己完成)
③openid的获取:
可以看官方文档,这些文档都不是一个文档,所以很容易找不到。
具体做法:
- 首先,在客户端点击支付后,必须先跳转到这个地址:
- https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
- 1)redirect_uri,是你使用JS-SDK的页面的地址,也就是wx.chooseWXPay所在页面的地址,必须进行urlencode,跳转过去后能在url中尾部看到?code=CODE&state=STATE,把CODE从url中取出来。
- 2)使用GET方法调用这个接口https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code,把刚取到的code填进去,还有别的参数不要填错了。
3) 返回的json格式中就能取到openid了。- ④prepayid的获取:
这部分仍然在后台进行,使用post并且是XML格式发送数据,也就是说发送一段XML格式的字符串就是了,格式如下:
- String text = "<xml>"+
- "<appid>"+appid+"</appid>"+
- "<body>"+body+"</body>"+
- "<mch_id>"+mch_id+"</mch_id>"+
- " <nonce_str>"+nonce_str+"</nonce_str>"+
- " <notify_url>"+notify_url+"</notify_url>"+
- "<openid>"+openid+"</openid>"+
- "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
- "<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+
- "<total_fee>"+total_fee+"</total_fee>"+
- "<trade_type>"+"JSAPI"+"</trade_type>"+
- "<sign>"+sign+"</sign>"+
- "</xml>";
说明:
1)spbill_create_ip是支付终端的IP地址
2)notify_url不用urlencode
3)total_fee不能是小数,因为单位是分
4)签名上面已经给了,就是用key,value方式把除了sign以外的所有字符串连起来,最后加上"&key=xxx",然后MD5再转大写。
5)out_trade_no,这个是自己标记自己商品号的一个号,不能重复,所以建议用时间戳+一些自己的规则。
6)body是中文时报签名错误:首先确保中文是utf-8,然后转成iso8859-1,可以用下面这句代码:
- text = new String(text.getBytes(), "iso8859-1");
注意:①假如是自己在本地调用接口,写死一个中文去测试,请确保你的页面编码是utf-8,像我这种不太注意的,本来页面用了GBK编码,所以怎么试都不成功,怎么查编辑文件用什么编码,自行谷歌百度自己的编辑器的设置编码在哪里。
②tomcat的编码,如果是从ajax把中文的body传到后台,请注意tomcat的编码设置,确保拿到的中文是utf-8。
7)上面的做好了,就可以拿到prepayid了,将prepayid和自己生成的nocestr和timestamp以及刚才生成的签名sign传回给前台,并且填到wx.chooseWXPay里,尝试支付。
8)“商户签名错误”:假如已经拿验算工具查过,签名是正确的,仍然报错,那必然是这个原因——timeStamp,S是大写的!!。虽然官网已经做出了提醒,但是绕了那么多圈之后你早就不记得这件事了,或者说没搞清楚,没错,签名的时候timeStamp的S必须是大写的,然后前台的wx.chooseWXPay里的timestamp是小写的,就是那么的神奇!
9)当前的页面URL未注册:
微信公众账户里的微信支付-支付测试,看看填写的地址是不是支付所在的地址。
10)系统繁忙,正在升级,请稍后再试:
基本上不会是系统繁忙,这是我整个过程遇到微信接口唯一的一次报错错误,请检查签名参数,着重检查中文编码问题。
- 3、支付部分
- 终于,突过重重难关,弹出支付图标并且可以支付了,但是怪并没有打完,你的回调接口可能还没完善,这篇文章对回调部分的描述挺不错的,网上能下到JAVA的DEMO,但有些部分已经不能用了,主要不能用的部分是拿到数据的时候需要用inputstream去处理,而不能通过request直接读取。
回调要要做的事:
①拿到反馈数据
只要支付成功了,微信会推送一个XML格式的数据过来,JAVA请用下面的代码解析出来
- public static byte[] readBytes(InputStream in) throws IOException {
- byte[] temp = new byte[in.available()];
- byte[] result = new byte[0];
- int size = 0;
- while ((size = in.read(temp)) != -1) {
- byte[] readBytes = new byte[size];
- System.arraycopy(temp, 0, readBytes, 0, size);
- result = SystemUtil.mergeArray(result,readBytes);
- }
- return result;
- }
②校验签名
微信支付传过来数据,但未必是对的,所以把里面的签名拿出来,把别的变量拿出用keyvalue同样的方式加密再和签名对比,一样的就是对的。
③返回SUCCESS
④微信会在30分钟内进行8次回调,这是担心你网络问题等拿不到支付后的数据,所以你要判断这个东西是否已经成功处理过了
⑤处理:不外乎就是拿出订单号等,写入自己的数据库里。
- 4、完成部分
- wx.chooseWXPay({
- timestamp: 0, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
- nonceStr: '', // 支付签名随机串,不长于 32 位
- package: '', // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
- signType: '', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
- paySign: '', // 支付签名
- success: function (res) {
- // 支付成功后的回调函数
- }
- });
- 看到“支付成功后的回调函数”了吗?就在这里面写完成后跳转的页面,location.href=xxx,完结了~
- 大功告成……唉,真不好意思说大功,像支付宝一样的话也就一天半天的事,这个却整了那么久。
- 给官方的建议是,Demo能否出现在显眼的位置,能否做一个针对DEMO的文档或者说明(例如这个demo是适合哪个版本的都没说),对DEMO做相应修改或者填写各种key和id就行了,顶多再教一下配置些什么,毕竟很多东西都是死的,不需要用户全部敲一遍,只不过按照规则填就是了。
JS-SDK微信支付开发攻略的更多相关文章
- 微信支付开发 c# SDK JSAPI支付开发的流程和微信大坑
微信支付开发流程 1. 开通微信支付功能 省略 2. 下载微信的C#版的微信SDK 下载连接:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chap ...
- PHP微信支付开发实例
这篇文章主要为大家详细介绍了PHP微信支付开发过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 PHP微信支付开发过程,分享给大家,供大家参考,具体内容如下 1.开发环境 Thinkphp 3. ...
- 微信支付开发+{ping++}微信支付托管
------------------------微信支付接口------------------------------- 微信支付开发并没有想象中的那么难,主要是微信提供了sdk. 微信公众号必须是 ...
- PHP微信支付开发之扫描支付(模式二)后如何回调
其实在写这篇文章的时候感觉自己已经落伍了,不过笔者在百度上搜索"微信支付开发之扫描支付(模式二)后如何回调"寻找答案时,发现依旧有很多朋友没有解决这个问题,所以就把自己的解决思路分 ...
- PHP微信支付开发
此链接https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_2,是微信官方的示例,无效,报错. 1.申请微信支付的开通条件?什么样的账号可以 ...
- 微信支付开发出现redirect_uri参数错误的解决方法
我们在进行微信支付开发的时候会遇到出现“redirect_uri参数错误”这种情况,怎么办呢?下面就是我总结出现这种“redirect_uri参数错误”的七种可能情况,以及解决方式. 1.可能原因①: ...
- 微信支付开发h5调用
这两天做微信支付开发.碰到大坑.纠结死我了.好不容做完. 后台java:直接上代码:注意区分前后端的变量大小写... @RequestMapping(value = "/index" ...
- 微信支付开发(11) Native支付
关键字:微信公众平台 微信支付 Native原生支付作者:方倍工作室原文:http://www.cnblogs.com/txw1958/p/wxpay-native.html 由于微信支付接口更新,本 ...
- Android开发 --微信支付开发(转载!)(开发工具:Eclipse)
Android_APP 微信支付接口开发 日期:2015-10-06 12:47:33 作者: 来源: 人气:3549 1.首先说一下我们在开发微信支付接口的时候遇到最多和最疑惑的问题,那就是明明 a ...
随机推荐
- SqlServer SSAS IIS 部署
参考MSDN官网:http://technet.microsoft.com/zh-cn/library/gg492140.aspx 注意事项: 网络上有文章说,最后验证是否成功 是在浏览器中输入url ...
- JavaScript高级程序设计49.pdf
HTML5事件 contextmenu事件 contextmenu事件是冒泡的,可以将事件处理程序指定到document,这个事件的目标是用户操作的元素,在兼容DOM的浏览器中使用event.prev ...
- HTML5 移动应用开发环境搭建及原理分析
开发环境搭建: 一.Android 开发平台搭建 安装java jdk:\\10.194.151.132\Mewfile\tmp\ADT 配置java jdk 1) 新建系统变量,JAVA_HOME ...
- MSW下wxWidgets的安装与编译
教程摘自网上各大博客.贴吧.论坛,结合自己的实践做了一些实质性的修改. 一.安装 首先从http://sourceforge.net/projects/wxwindows/files/2.8.12/w ...
- openstack 调试
- eclipse 反编译class 文件 插件-jad
1.下载 jad.exe http://pan.baidu.com/s/1i3Ga33n 2.下载jadeclipse http://pan.baidu.com/s/1bn4H1iZ 放在ecli ...
- 使用gulp自动化配置环境变量
使用gulp拷贝文件,可以完成开发api环境变量的配置,例如公司的线上环境有三个: 1.alpha线上测试环境 2.dev线上测试环境 3.test 本地测试环境 (4.production 正式系统 ...
- tomcat多域名配置
1.找到你的tomcat然后在conf文件中找到server.xml打开: <Server port="8005" shutdown="SHUTDOWN" ...
- 懂,你的App生,不懂,死!
近期有一些开发人员.创业公司的人加我微信viyi88,咨询一些关于自己App的事情.被问得最多的可能就是:"我的App怎样推广添加下载量?"而且信誓旦旦地说自己的App做得非常好, ...
- LabVIEW中的UDP通信
UDP(user datagram protoco1)提供向接收端发送信息的最简便的协议,与TCP不同,UDP不是面向连接的可靠数据流传输协议,而是面向操作的不可靠数据流传输协议.UDP在数据传输之前 ...