借图一用,我的认为这张图包含了微信支付的架构理念(https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3)php
商户系统和微信支付系统主要交互:前端
实现流程: node
=> 获取微信用户的openid (小程序端获取传到后台)express
=> 预下单获取prepay_id ,sign签名(后台根据相关参数进行签名)npm
=> 小程序端发送支付请求(根据后台返回的prepay_id和sign)json
//小程序端
wx.login({
success(res) {
if (res.code) {
// 发起网络请求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
},
success:function(res){
let openId = res.data.openid//获取后台返回的openid
}
})
} else {
console.log('登陆失败!' + res.errMsg)
}
}
})
//nodejs端
var request = require('request')
const JSCODE = ''(前端传过来的值)
let wxUrl = "https://api.weixin.qq.com/sns/jscode2session"//小程序appid,secret等信息存在后台的配置文件中
var url = wxUrl + 'appid=' + Config.wxLogin.appid + '&secret=' + Config.wxLogin.secret
var js_code = req.query.js_code
url = url + '&js_code=' + js_code + '&grant_type=authorization_code'
request(url, function (error, response, body) {
if (error) {
var results = Util.formatErrorRes(error);
res.json(results);
return }
var results = Util.formatRes(body);
res.json(results);
})复制代码
2. 后台根据相关参数获取prepay_id,sign签名小程序
=>后端格式化参数(根据小程序统一下单文档的须要)后端
=>后台带参数请求微信统一下单地址(其中notify_url后端接受支付结果的接口地址)微信小程序
=>请求成功解析小程序返回的xml格式数据(引入npm包xmlreader,主要获取prepay_id)api
=>根据返回的值进行二次签名生成签名字符串(与prepay_id一块儿返回给前端)
=>前端根据返回的签名和prepay_id进行支付请求
=>微信支付成功,微信服务器将支付结果发到以前设置的notify_url
=>根据微信后台返回的结果,更新用户信息
注:此部分代码较多,近期会整理下放在GitHub,若是哪位道友着急须要可在下方评论中说明
微信官方回答
1) 使用微信的在线签名工具检查签名是否和程序生成的一致
https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1
签名工具用谷歌打开。选择MD5,XML,而后把请求参数xml放进去,就能校验签名。
2)若是和微信的在线签名工具一致,说明程序没有错误,肯定是API密钥错误
(被别人改动或者记错了)在商户平台的帐户信息中更改API密钥(帐户设置-安全设置-API安全),
15分钟后生效
2.1)统一下单用的是A商户号,也必须是A商户号登录商户平台设置key才对。
2.2)要注意统一下单请求参数中total_fee参数的类型是int类型。
3) 若是和微信的在线签名工具不一致,说明程序有错误,
常见的错误多是:
3.1) 编码问题,确保全部的都是utf-8的. 若是有中文, 能够先把中文改为英文从新签名,
看是否签名错误,若是英文不会错中文才会错,基本确定是编码问题
3.2:)消息中字段大小写和文档中彻底一致复制代码
按照上述需求进行配置就能够解决支付签名错误的问题了。
2.express微信支付回调值req.body为空{}
支付返回的格式是xml,查找到缘由是express4.x里将body-parser分离出来,变成像其余中间件的使用方式,
因此咱们须要在app.js中增长中间件
var bodyParser = require("body-parser");
require("body-parser-xml")(bodyParser);
// 解析支付回调的xml数据
app.use(bodyParser.xml({
limit: "1MB",
// Reject payload bigger than 1 MB
xmlParseOptions: {
normalize: true,
normalizeTags: true,
explicitArray: false
},
verify: function(req, res, buf, encoding) {
if(buf && buf.length) {
// Store the raw XML
req.rawBody = buf.toString(encoding || "utf8");
}
}}));复制代码
参数的格式必须严格按照文档要求,参数须要用使用驼峰(以前用下划线app_id这种类型一 直报参数错误...)
var ret = {
appId: appid,
package:'prepay_id='+prepayid,
nonceStr: noncestr,
signType:'MD5',
timeStamp: timestamp,
};复制代码
5.没有支付权限
检查该小程序帐号是否已经获取了支付资格。