微信公众号支付流程(Node实现)
前言
花费了一天时间,调通了微信公众号支付。作下记录,方便以后再次填坑。先声明,微信公众号支付,不同于微信H5支付,这点在本文结束时再详细说明。
微信配置
设置测试目录
在微信公众平台设置,栏目见下图。支付测试状态下,设置测试目录,测试人的微信号添加到白名单,发起支付的页面目录必须与设置的精确匹配。并将支付链接发到对应的公众号会话窗口中才能正常发起支付测试。注意正式目录一定不能与测试目录设置成一样,否则支付会出错。
设置正式支付目录
根据图中栏目顺序进入修改栏目,勾选JSAPI网页支付开通该权限,并配置好支付授权目录,该目录必须是发起支付的页面的精确目录,子目录下无法正常调用支付。具体界面如图所示:
交互流程
业务流程时序图
首先看下微信官方给出的交互流程:
服务器交互
微信公众号支付的流程,简而言之只有两步。第一步,下单,拿到prepay_id等信息;第二步,利用第一步拿到的prepay_id等信息进行支付。
代码
Node端
// 微信支付
exports.weixinpay = function(req, res){
var orderId = req.params.orderId;
var selectSum = req.params.selectSum;
var token = req.params.token;
// 获取code
if(!req.query.code){
var r_url = 'http://' +config.host+'/artist/weixinpay/'+orderId+'/'+selectSum+'/'+token;
var url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='+config.weixin.appid+'&redirect_uri='+urlencode(r_url)+'&response_type=code&scope=snsapi_userinfo&state=111#wechat_redirect';
res.redirect(url);
}else{
var code = req.query.code;
var state = req.query.state;
var ep = new eventproxy();
ep.all('userInfo',function(userInfoData){
var userInfoData = JSON.parse(userInfoData);
res.render('artist/weixinpay',{
// 其他数据
openid: userInfoData.openid,
orderId: orderId,
selectSum: selectSum,
token: token
});
});
// 获取用户信息userInfo
}
}
exports.weixinpay2 = function(req, res){
var wxParamUrl = config.apihost + '/order/getH5SubOrderforWechat';
var param = {
orderId: req.query.orderId,
selectSum: req.query.selectSum,
accessToken: req.query.token,
openId: req.query.openid
};
request.post({url: wxParamUrl,form: JSON.stringify(param)},function(error, response, body){
res.render('artist/weixinpay2',{
// 其他数据
wxParam: JSON.parse(response.body)
});
});
}
上面的代码看起来很奇怪,为什么需要一个weixinpay2函数?代码全部放在weixinpay函数里面,然后在weixinpay.html里调用微信支付接口,不是很好么?这个,就涉及到支付目录的问题了。weixinpay函数中,微信授权获取用户信息后的回调url,目录太深,而且不确定,因为我们是通过目录来传递参数的。这样,就无法在微信公众号上面设置支付授权目录。所以,我们不能在weixinpay.html这个页面发起支付请求,只能把参数转发给下一个weixinpay2.html页面,在weixinpap2.html中发起支付请求。
那么,为什么获取用户信息后的回调url目录太深?直接把orderId等信息当做参数放在回调url后面不就可以了吗?很遗憾,回调url无法带入你的自定义参数。因此,只能把参数当做回调url的一部分,也就是目录的一部分。
综上,weixinpay函数负责获取用户的openid,weixinpay.html负责跳转weixinpay2.html;weixinpay2函数负责获取调用微信JSAPI的参数,weixinpay2.html负责调用微信JSAPI。
html
<!--weixinpay.html-->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>微信支付</title>
</head>
<body>
<a id="weixin-link" href="/artist/weixinpay2?orderId=<%= orderId%>&selectSum=<%= selectSum%>&token=<%= token%>&openid=<%= openid%>" style="display: none">微信支付</a>
<script>
var link = document.getElementById('weixin-link');
link.click();
</script>
</body>
</html>
<!--weixinpay2.html-->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>微信支付</title>
</head>
<body>
<input id="appId" type="hidden" value="<%= wxParam.obj.appid%>">
<input id="timeStamp" type="hidden" value="<%= wxParam.obj.timestamp%>">
<input id="nonceStr" type="hidden" value="<%= wxParam.obj.noncestr%>">
<input id="package" type="hidden" value="<%= wxParam.obj.packagestr%>">
<input id="signType" type="hidden" value="MD5">
<input id="paySign" type="hidden" value="<%= wxParam.obj.sign%>">
<script>
function onBridgeReady(){
var appId = document.getElementById('appId').value;
var timeStamp = document.getElementById('timeStamp').value;
var nonceStr = document.getElementById('nonceStr').value;
var package = document.getElementById('package').value;
var signType = document.getElementById('signType').value;
var paySign = document.getElementById('paySign').value;
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": appId, //公众号名称,由商户传入
"timeStamp":timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": nonceStr, //随机串
"package": package,
"signType": signType, //微信签名方式:
"paySign": paySign //微信签名
},
function(res){
WeixinJSBridge.log(res.err_msg);
//alert(res.err_code + res.err_desc + res.err_msg);
if (res.err_msg == "get_brand_wcpay_request:ok") {
window.location.href = '/artist/alipayresult?trade_status=TRADE_SUCCESS';
// 执行跳转页面....
} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert ("用户取消支付!");
} else {
alert ("支付失败!");
}
}
);
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
</script>
</body>
</html>
为了加快执行速度,这里的两个页面中,都使用原生的js来实现页面逻辑。
错误
支付验证签名失败
很明显,支付验证签名失败。怎么判断算出的签名是否正确?使用微信支付接口签名校验工具。
校验方式选择自定义参数,把需要签名的参数名称和参数值输入页面,点击生成签名即可。
当前页面的URL未注册
不好意思,这个错误忘记截图了。借来了一张图,凑合着看。
这个问题,是由于调用支付接口的url不对!那么,怎样是对的呢?举个栗子:如果调用支付接口的url为http://wx.voidking.com/pay/weixinpay
,那么微信公众平台上的支付授权目录应该设置为http://wx.voidking.com/pay/
。也就是说,支付授权目录应该设置为调用支付接口的url的上一级目录。
支付成功
后记
微信公众号支付,两个缺点,一是必须在微信浏览器使用,二是必须有一个拉取用户信息的步骤。但是我们发现,很多网站,在其他浏览器也可以使用微信支付,也不需要拉取用户信息,这是怎么回事?
因为,这是两种不同的支付方式!今天我们讨论的,叫做微信公众号支付;而在其他浏览器中调用微信支付,叫做微信H5支付!
更多关于微信H5支付的内容,请参考微信H5支付官方文档。
书签
微信支付开发文档——公众号支付
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1
微信支付接口签名校验工具
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
非微信内置浏览器中的网页调起微信支付的方案研究
http://blog.csdn.net/ahence/article/details/51317814
微信支付|商户平台开发者文档
https://pay.weixin.qq.com/wiki/doc/api/wap.php?chapter=15_1
【微信支付V2.0】H5支付实例
http://wxpay.weixin.qq.com/pub_v2/pay/wap.v2.php
微信公众号支付流程(Node实现)的更多相关文章
- 到处是坑的微信公众号支付开发(java)
之前公司项目开发中支付是用阿里的支付做的,那叫一个简单,随意:悲催的是,现在公司开发了微信公众号,所以我步入了全是坑的微信支付开发中... ------------------------------ ...
- 微信公众号支付备忘及填坑之路-java
一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...
- 使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发
概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很 ...
- 微信公众号支付开发全过程 --JAVA
按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的 ...
- 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...
- C#版微信公众号支付|微信H5支付|微信扫码支付问题汇总及解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存.代码在文章结尾处,有需要的 ...
- java版微信公众号支付(H5调微信内置API)
最近需要做微信公众号支付,网上找了大堆的代码,大多都只说了个原理,自己踩了太多坑,所有的坑,都会再下面的文章中标注,代码我也贴上最全的(叫我雷锋)!!! 第一步:配置支付授权目录 你需要有将你公司的微 ...
- 微信公众号支付(JSAPI)对接备忘
0 说明 本文里说的微信公众号支付对接指的是对接第三方支付平台的微信公众号支付接口. 非微信支付官方文档里的公众号支付开发者文档那样的对接.不过,毕竟腾讯会把一部分渠道放给银行或有支付牌照的支付机构, ...
- thinkphp.2 thinkphp5微信支付 微信公众号支付 thinkphp 微信扫码支付 thinkphp 微信企业付款5
前面已经跑通了微信支付的流程,接下来吧微信支付和微信企业付款接入到thinkphp中,版本是3.2 把微信支付类.企业付款类整合到一起放到第三方类库,这里我把微信支付帮助类和企业付款类放到同一个文件了 ...
随机推荐
- Swift(一,创建对象,类型推导,基本运算,逻辑,字符串,数组,字典)
swift用起来刚开始感觉有点怪怪的,但用了一段时间觉得还是挺好用的,哈哈.毕竟都是要有一个过程的嘛. 我就写一些自己在使用swift的时候的注意点吧,如有不正之处,还请指正! 一.在开发中优先使用常 ...
- iOS 8创建交互式通知-备
iOS 8提供了一个令人兴奋的新API来创建交互式通知(interactive notifications),它能让你在你的应用之外为用户提供额外的功能.我发现网上还没有关于如何实现它的比较好的示例教 ...
- 使用URLClassLoader类载入类实例
Tomcat当中在接受到要调用的Servlet请求后,需要载入相应的Servlet类,然后创建Servlet类实例,从而调用Servlet类实例的service()方法 下面实例的场景,request ...
- iOS 开发常用的一些工具
http://www.itjhwd.com/ios-tool/ 通用工具 HomeBrew:OS X上非常出色的包管理工具. 源码控制 Git:分布式版本控制系统和源码管理系统,其优点是:快和简单易用 ...
- php版的求表达式的真值表-TrueValueTable
贴上代码: <?php error_reporting(E_ALL & ~E_NOTICE); $expression=$_GET['TrueTable']; //读取输入框数据 if( ...
- String、StringBuffer和StringBuilder——个人学习
1.首先说一下他们的名称区别: String——字符串常量,StringBuffer——字符串变量(线程安全),StringBuilder——字符串变量(非线程安全) 从名称就可以很明显的看出他们的基 ...
- shuffle ----- mr 董西城
http://dongxicheng.org/framework-on-yarn/apache-spark-shuffle-details/
- 《Zero to One》的一些读书笔记
第一章<The Challenge of the Future>:全球化是横向的扩张,只能复制以前就有的成功,而科技创新是纵向的扩张,是创造以前不存在的东西.没有科技创新,只有全球化,这个 ...
- Warm up
hdu4612:http://acm.hdu.edu.cn/showproblem.php?pid=4612 题意:给你一个无向连通图,问加上一条边后得到的图的最少的割边数; 题解:首先对原图求割边数 ...
- WINDOWS下简单操作SQLITE3
有测试操作的时候,还是很好的说~~~ 找个sqlite3.txt下载 sqlite3.exe db.sqlite3 SQLite version 3.7.13 2012-06-11 02:05:22 ...