借圖一用,我的認爲這張圖包含了微信支付的架構理念(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.沒有支付權限
檢查該小程序帳號是否已經獲取了支付資格。