(1) WeChat official account and WeChat merchant platform configuration
Configure according to the tutorial on the WeChat public platform
1. Set up payment directory
Please make sure that the requested directory during the actual payment is consistent with the directory configured in the background, otherwise the WeChat payment will not be able to be invoked successfully.
Set your official account payment directory on the WeChat merchant platform (pay.weixin.qq.com), and set the path: merchant platform --> product center --> development configuration, as shown in Figure 7.7. The official account payment will verify whether the request source has been configured on the merchant platform when requesting payment, so you must ensure that the payment directory has been configured correctly, otherwise the verification will fail and the payment request will not succeed.
Figure 7.7 WeChat Official Account Payment-Payment Directory Configuration
2. Set authorized domain name
When developing official account payment, the user’s openid must be transmitted in the unified order interface, and to obtain openid, you need to set the domain name for obtaining openid on the public platform. Only the domain name that has been set is a valid domain name for obtaining openid, otherwise Will get failed. The specific interface is shown in Figure 7.8:
Figure 7.8 WeChat webpage authorized domain name settings
Three, configure the merchant secret key key
Reference article https://jingyan.baidu.com/article/75ab0bcbbf7034d6864db2c3.html
Note that after configuring the secret key, you must save the secret key yourself, and you cannot view the secret key on the merchant platform. The following signature algorithm requires the merchant secret key.
(Two) unified order
One, configuration and parameters
Refer to the documentation, the things to note are:
1. The callback address notify_url of WeChat payment result notification must be port 80, if it is not port 80, it can be reverse proxy through nginx
2. Transaction type here is the official account payment, fill in JSAPI
3.openid, when the official account payment is trade_type=JSAPI, this parameter must be passed, this parameter is the openid obtained after the front-end WeChat login
Second, the code implementation
1. Nodejs as the background to achieve a unified order interface
h5_order: function(attach, body, mch_id, openid, out_trade_no, total_fee, notify_url,spbill_create_ip,scene_info) {
var deferred = Q.defer();
var appid = "wx4280cd3b0ecf2a38";//"wx7df91d705b3f0a15"; // h5的appid
var nonce_str = this.createNonceStr();
var trade_type = "JSAPI";
var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
var spbill_create_ip = "115.192.87.205";//写死了这边
var formData = "<xml>";
formData += "<appid>" + appid + "</appid>"; //appid 必填
//formData += "<attach>" + attach + "</attach>"; //附加数据
formData += "<body>" + body + "</body>"; //必填
formData += "<mch_id>" + mch_id + "</mch_id>"; //商户号 //必填
formData += "<nonce_str>" + nonce_str + "</nonce_str>"; //随机字符串,不长于32位。 //必填
formData += "<notify_url>" + notify_url + "</notify_url>"; //必填
formData += "<openid>" + openid + "</openid>";
formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>"; //必填
formData += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"; //IP地址需要动态获取 //必填
formData += "<total_fee>" + total_fee + "</total_fee>"; //必填
formData += "<trade_type>" + trade_type + "</trade_type>"; //必填
//formData += "<sign>" + this.getSign(appid, mch_id, "", body, nonce_str) + "</sign>"; // getSign: function(appid, mch_id, device_info, body, nonce_str) {
//formData += "<scene_info>" + JSON.stringify(scene_info) + "</scene_info>";
formData += "<sign>" + this.signOne(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, "JSAPI") + "</sign>";
formData += "</xml>";
//console.log("formData:"+formData);
var self = this;
request({
url: url,
method: 'POST',
body: formData
}, function(err, response, body) {
if (!err && response.statusCode == 200) {
console.log(body);
var parser = new xml2js.Parser({ trim:true, explicitArray:false, explicitRoot:false });//解析签名结果xml转json
parser.parseString(body, function(err, result){
var prepay_id = result['prepay_id'];
var timeStamp = self.createTimeStamp();
var package="prepay_id="+prepay_id;
var _paySignjs = self.signTwoH5(appid, nonce_str, package,timeStamp,"MD5");
var args = {
appId: appid,
package: package,
timeStamp: timeStamp,
nonceStr: nonce_str,
paySign: _paySignjs
};
//console.log("进行二次签名后数据", args);
deferred.resolve(args);
});
} else {
console.log(body);
}
});
return deferred.promise;
},
2. Signature function signOne:
signOne: function(appid, attach, body, mch_id, nonce_str, notify_url, openid, out_trade_no, spbill_create_ip, total_fee, trade_type) {
//参数名ASCII码从小到大排序(字典序)
var ret = {
appid: appid,//ok
//attach: attach,
body: body,//ok
mch_id: mch_id,//ok
nonce_str: nonce_str,//ok
notify_url: notify_url,
openid: openid,
out_trade_no: out_trade_no,
spbill_create_ip: spbill_create_ip,
total_fee: total_fee,
trade_type: trade_type //类型
};
var string = this.raw(ret);
string = string + '&key=' + key; //key为在微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
console.log("signOne string:"+string);
var crypto = require('crypto');
var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');//md5加密操作
return sign.toUpperCase();//转换成大写字母
},
//拼接
raw: function(args) {
var keys = Object.keys(args);
keys = keys.sort()
var newArgs = {};
keys.forEach(function(key) {
newArgs[key] = args[key];
});
var string = '';
for (var k in newArgs) {
string += '&' + k + '=' + newArgs[k];
}
string = string.substr(1);
return string;
}
2. Signature function signTwoH5:
signTwoH5: function(appid, nonceStr, package,timestamp,signType) {
var ret = {
appId: appid,
nonceStr: nonceStr,
package: package,
timeStamp: timestamp,
signType:signType,
};
var string = this.raw(ret);
string = string + '&key=' + key;
console.log("signTwo string: " + string);
var sign = crypto.createHash('md5').update(string, 'utf8').digest('hex');
return sign.toUpperCase();
}
3. Generate timestamp and random string function
// 随机字符串产生函数
createNonceStr: function() {
return Math.random().toString(36).substr(2, 15);
},
// 时间戳产生函数
createTimeStamp: function() {
return parseInt(new Date().getTime() / 1000) + '';
},
4. The server generates the pre-payment order number and other information and sends it to the front-end, and the front-end WeChat built-in browser invokes the payment code as follows:
Any error messages can be printed out with alert(JSON.stringify(res))