微信公众号支付流程(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 把微信支付类.企业付款类整合到一起放到第三方类库,这里我把微信支付帮助类和企业付款类放到同一个文件了 ...
随机推荐
- 如何设置路由器实现静态IP配置
一.概述 嵌入式开发者,经常面对这样的环境:PC(windows)+虚拟机(linux)+开发板.我们希望三者都能相互通信,而且可以联网. 对于实验室只提供一根网线,而自己没有额外的增加端口数量的设备 ...
- bzoj 1305: [CQOI2009]dance 二分+網絡流判定
1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 1340 Solved: 581[Submit][Sta ...
- 【转】python3 发邮件实例(包括:文本、html、图片、附件、SSL、群邮件)
特别留意群邮件方式,这是工作中用得多的. 附件,HTML,图片,都需要的. 文件形式的邮件 [python] view plain copy 1.#!/usr/bin/env python3 2.#c ...
- Linux下查看CPU信息
在linux操作系统中,CPU的信息在启动的过程中被装载到虚拟目录/proc下的cpuinfo文件中,我们可以通过 cat /proc/cpuinfo 查看一下:
- LeetCode解题报告:Linked List Cycle && Linked List Cycle II
LeetCode解题报告:Linked List Cycle && Linked List Cycle II 1题目 Linked List Cycle Given a linked ...
- 利用纯java捕获和播放音频
参考: 1.http://www.cjsdn.net/doc/jdk60/javax/sound/sampled/package-summary.html 2.http://www.cjsdn.net ...
- 【转】更新SDK后,打包APK时报 the zipalign tool was not found in the sdk
原文网址:http://wyong.blog.51cto.com/1115465/1546632 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任 ...
- QTP自动化测试权威指南 连载(一)
第一章 简介 什么是自动化测试 自动化测试是对一个已有的手工测试过程减少并尽可能排除人工干预的过程. 什么时候适合做自动化测试 下面是一组适合将手工测试自动化的考量因素: ● 测试需要经常重复. ● ...
- 【转】unity3d 各种优化综合
检测方式: 一,unity3d 渲染统计窗口 Game视窗的Stats去查看渲染统计的信息: 1.FPS fps其实就是 frames per second,也就是每一秒游戏执行的帧数,这个数值越 ...
- (java) Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * Lis ...