前言

花费了一天时间,调通了微信公众号支付。作下记录,方便以后再次填坑。先声明,微信公众号支付,不同于微信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实现)的更多相关文章

  1. 到处是坑的微信公众号支付开发(java)

    之前公司项目开发中支付是用阿里的支付做的,那叫一个简单,随意:悲催的是,现在公司开发了微信公众号,所以我步入了全是坑的微信支付开发中... ------------------------------ ...

  2. 微信公众号支付备忘及填坑之路-java

    一.背景 最近公司给第三方开发了一个公众号,其中最重要的功能是支付,由于是第一次开发,遇到的坑特别的多,截止我写博客时,支付已经完成,在这里我把遇到的坑记录一下(不涉及退款).不得不吐槽一下,腾讯这么 ...

  3. 使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发

    概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很 ...

  4. 微信公众号支付开发全过程 --JAVA

    按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的 ...

  5. 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结

    最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...

  6. C#版微信公众号支付|微信H5支付|微信扫码支付问题汇总及解决方案总结

    最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存.代码在文章结尾处,有需要的 ...

  7. java版微信公众号支付(H5调微信内置API)

    最近需要做微信公众号支付,网上找了大堆的代码,大多都只说了个原理,自己踩了太多坑,所有的坑,都会再下面的文章中标注,代码我也贴上最全的(叫我雷锋)!!! 第一步:配置支付授权目录 你需要有将你公司的微 ...

  8. 微信公众号支付(JSAPI)对接备忘

    0 说明 本文里说的微信公众号支付对接指的是对接第三方支付平台的微信公众号支付接口. 非微信支付官方文档里的公众号支付开发者文档那样的对接.不过,毕竟腾讯会把一部分渠道放给银行或有支付牌照的支付机构, ...

  9. thinkphp.2 thinkphp5微信支付 微信公众号支付 thinkphp 微信扫码支付 thinkphp 微信企业付款5

    前面已经跑通了微信支付的流程,接下来吧微信支付和微信企业付款接入到thinkphp中,版本是3.2 把微信支付类.企业付款类整合到一起放到第三方类库,这里我把微信支付帮助类和企业付款类放到同一个文件了 ...

随机推荐

  1. 轻量级表格插件Bootstrap Table。拥有强大的支持固定表头、单/复选、排序、分页、搜索及自定义表头等功能。

    Bootstrap Table是轻量级的和功能丰富的以表格的形式显示的数据,支持单选,复选框,排序,分页,显示/隐藏列,固定标题滚动表,响应式设计,Ajax加载JSON数据,点击排序的列,卡片视图等. ...

  2. Chain of Responsibility

    比较经典的距离是请假申请(<大话设计模式>中的例子),请假是要逐级判断,只有级别到了才有权利审批,从构造上面其实"装饰"模式和"职责链"之间有相通的 ...

  3. [CF Round #294 div2] D. A and B and Interesting Substrings 【Map】

    题目链接:D. A and B and Interesting Substrings 题目大意 给定26个小写字母的权值,一共26个整数(有正有负). 给定一个小写字母组成的字符串(长度10^5),求 ...

  4. iOS:关于获取网络类型和运营商信息

    目录 1. 获取运营商网络类型 2. 获取运营商信息 返回目录 1. 获取运营商网络类型 Apple的Reachability Sample看起来不错,但是只可以判断是否连接到互联网和是否连接Wifi ...

  5. Spring 操作Weblogic JDNI数据源

    <!--Data Source--> <jee:jndi-lookup id="nssb_1122_cs" jndi-name="jdbc/nssb_1 ...

  6. PYTHON文本处理指南之日志LOG解析

    处理特定字段的内容,并指指定条件输出. 注意代码中用一个方法列表,并且将方法参数延后传递. GOOGLE作过PYTHON代码的水平,就是不一样呀. 希望能学到这种通用的技巧. 只是,英文PDF看起来有 ...

  7. 【HDOJ】1421 搬寝室

    DP.这题都能TLE,发现memset有时居然比for还要慢. #include <stdio.h> #include <stdlib.h> #include <stri ...

  8. 【转】Xcode 7 真机调试详细步骤

    原文网址:http://www.jianshu.com/p/fa5f90b61ad6 文/ldjhust(简书作者)原文链接:http://www.jianshu.com/p/fa5f90b61ad6 ...

  9. 【转】Android--UI之ProgressBar--不错

    原文网址:http://www.cnblogs.com/plokmju/p/android_progressbar.html 前言 开门见山,开篇明意.这篇博客主要讲解一下Android中Progre ...

  10. java生成随机整数

    1. 使用Random类的nextInt方法: Random rand = new Random(); rand.nextInt(max);, 此时输出[0,max),注意右边是开区间,如果需要设定最 ...