微信小程序实现微信支付功能流程
微信支付:
https://pay.weixin.qq.com/wiki/doc/api/index.html
图片说明
进行选择接入
图片说明
图片说明
步骤:
小程序调用登录接口,获取用户的openid
, wx.login(object)
, 通过调用接口获取登录凭证code
进行获取登录用户信息,包含用户的唯一标识(openid
)以及本次登录的会话密钥(session_key
).
用code
获取session_key
, 这是一个https
接口,开发者服务器使用登录凭证code
获取session_key
和openid
.其中session_key
是对用户数据进行保密的密钥.为了安全,不能将session_key
在网络上传输.
图片说明
获取的openid
商户在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。其实微信是提供java,net,php三种语言的封装包。
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
图片说明
微信小程序-支付
http://www.cnblogs.com/jcscript/p/6126722.html
需要支付的
perpay_id
wx.requestPayment(OBJECT)-微信支付
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
timeStamp | String | 是 | 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 |
nonceStr | String | 是 | 随机字符串。 |
package | String | 是 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*** |
signType | String | 是 | 签名算法,暂支持 MD5 |
paySign | String | 是 | 签名,具体签名方案参见小程序支付接口文档; |
wx.requestPayment({
"timeStamp": "",
"nonceStr": "",
"package": "",
"signType": "MD5",
"paySign": "",
"success":function(res){
},
"fail":function(res){
}
})
获取支付id
, res_pay
, 仅返回了perpay_id,还有随机字符串和签名
统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=***
签名,具体签名方案参见小程序支付接口文档
踩坑:
图片说明
图片说明
小程序支付->小程序调用起支付API
图片说明
微信小程序
API
同理
图片说明
https://developers.weixin.qq.com/miniprogram/dev/api/wx.requestPayment.html
图片说明
// 调起支付签名
function MixedencryMD5(res_paydata,randomString,timeStamp) {
return "appId=" + config.appid + "&nonceStr=" + randomString + "&package=prepay_id=" + res_paydata + "&signType=MD5" + "&timeStamp=" + timeStamp + "&key=" + config.key;
}
// 时间戳
function timeStamp() {
return parseInt(new Date().getTime() / 1000) + ''
}
/* 随机数 */
function randomString() {
var chars = 'A2345678';
var maxPos = chars.length;
var pwd = '';
for (var i = 0; i < 32; i++) {
pwd += chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
图片说明
注意: 时间戳和随机字符串,保证生成一次
微信支付开发文档-普通商户
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=1_1
图片说明
图片说明
开通微信支付和微信商户号,获取当前用户的openid
,通过调用wx.login
方法,可以得到用户的code
,然后开发者服务器使用登录凭证code
获取openid
.然后在获取prepay_id
和支付签名验证paySign
`appid`: "", // 公众号名称,由商户传入
`timeStamp`: "", // 时间
`nonceStr`: "", // 随机串
'package': 'prepay_id=',
'signType`: 'MD5'; // 微信签名方式,
'paySign': ""; // 微信签名
小程序通过wx.requestPayment
方法调用起支付功能.prepay_id
的获取和签名paySign
的获取.
图片说明
在小程序后台,申请微信支付,认证以后,微信支付申请审核通过后,商户在申请资料填写的邮箱中收取到由微信支付小助手发送的邮件,此邮件包含开发时需要使用的支付账户信息。
图片说明
图片说明
协议规则-商户接入微信支付
图片说明
安全规范
图片说明
appid: wxd
mch_id: 100
device_info: 10
body: test
nonce_str: ibA
第一步:对参数按照key=value的格式
stringA="appid=wx&body=test&device_info=10&mch_id=10100&nonce_str=ibJA";
第二步:拼接API密钥
stringSignTemp=stringA+"&key=" //注:key为商户平台设置的密钥key
sign=MD5(stringSignTemp).toUpperCase()="" //注:MD5签名方式
sign=hash_hmac("sha256",stringSignTemp,key).toUpperCase()="" //注:HMAC-SHA256签名方式
最终得到最终发送的数据
<xml>
<appid>wx</appid>
<mch_id>1000</mch_id>
<device_info>1</device_info>
<body>test</body>
<nonce_str>ibuA</nonce_str>
<sign>9A0A89CF3B7</sign>
</xml>
小程序支付
开放模式介绍-
appid
和mch_id
成对使用
微信支付开放的能力分2大类:普通模式和服务商模式
微信支付基础账号模型-普通模式
图片说明
普通服务商微信支付资金清算流程
图片说明
JSAPI 或 JSSDK 调起微信支付
图片说明
小程序支付模式
第一步开通微信支付功能,绑定微信支付商户号.
appid 小程序appid
mch_id 所绑定的商户号中的 mch_id
trade_type 请填写"JSAPI"
openid 使用 "wx.login" 接口获得的 openid
业务说明
账号申请指引
进行微信认证
小程序申请微信认证
认证入口:登录小程序—设置—基本设置—微信认证—详情
图片说明
小程序申请微信支付
图片说明
小程序绑定微信开放平台帐号
绑定小程序流程说明:登录微信开放平台(open.weixin.qq.com)—管理中心—公众帐号—绑定公众帐号
公众号关联小程序
关联流程:
登录公众号后台-小程序-小程序管理-添加-关联小程序
开通微信支付后,申请或复用微信支付商户号,新申请微信支付商户号或绑定一个已有的微信支付商户号,开通指引:
http://kf.qq.com/faq/140225MveaUz161230yqiIby.html
图片说明
注意事项:
图片说明
业务流程
小程序支付的流程图如下:
图片说明
图片说明
1、【[小程序登录API](https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html?t=20161122)】
2、【[统一下单API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1)】
3、【[再次签名](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3)】
4、【[支付结果通知API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7)】
5、【[查询订单API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_2)】
开发步骤
图片说明
HTTPS服务器配置
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=10_4
图片说明
小程序绑定已有商户号开通微信支付
http://kf.qq.com/faq/140225MveaUz161230yqiIby.html
小程序调起支付API
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=5
图片说明
示例代码:
wx.requestPayment(
{
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){},
'fail':function(res){},
'complete':function(res){}
})
商户平台安全使用
图片说明
小程序
案例:
/* 微信支付 */
goWxPay: function () {
var that = this;
wx.login({
success: function (res) {
console.log("获取login code",res.code);
that.getOpenId(res.code);
}
});
},
/* 获取openId */
getOpenId: function (code) {
var that = this;
wx.request({
url: "" + code,
method: 'GET',
success: function (res) {
that.unitedPayRequest(res.data.openid);
},
fail: function () {
},
complete: function () {
}
});
},
/*统一支付接口*/
unitedPayRequest: function(openid){
var that=this;
//统一支付签名
var appid = '';//appid必填
var body = '';//商品名必填
var mch_id = '';//商户号必填
var nonce_str = util.randomString();//随机字符串,不长于32位。
var notify_url = '';//通知地址必填
var total_fee = parseInt(0.01 * 100); //价格,这是一分钱
var trade_type = "JSAPI";
var key = ''; //商户key必填,在商户后台获得
var out_trade_no = '';//自定义订单号必填
var unifiedPayment = 'appid=' + appid + '&body=' + body + '&mch_id=' + mch_id + '&nonce_str=' + nonce_str + '¬ify_url=' + notify_url + '&openid=' + openid + '&out_trade_no=' + out_trade_no + '&total_fee=' + total_fee + '™_type=' + trade_type + '&key=' + key;
console.log("unifiedPayment", unifiedPayment);
var sign = md5.md5(unifiedPayment).toUpperCase();
console.log("签名md5", sign);
//封装统一支付xml参数
var formData = "<xml>";
formData += "<appid>" + appid + "</appid>";
formData += "<body>" + body + "</body>";
formData += "<mch_id>" + mch_id + "</mch_id>";
formData += "<nonce_str>" + nonce_str + "</nonce_str>";
formData += "<notify_url>" + notify_url + "</notify_url>";
formData += "<openid>" + openid + "</openid>";
formData += "<out_trade_no>" + that.data.ordernum + "</out_trade_no>";
formData += "<total_fee>" + total_fee + "</total_fee>";
formData += "<trade_type>" + trade_type + "</trade_type>";
formData += "<sign>" + sign + "</sign>";
formData += "</xml>";
console.log("formData", formData);
//统一支付
wx.request({
url: '',
method: 'POST',
head: 'application/x-www-form-urlencoded',
data: formData, //设置请求的 header
success: function (res) {
console.log("返回商户", res.data);
var result_code = util.getXMLNodeValue('result_code', res.data.toString("utf-8"));
var resultCode = result_code.split('[')[2].split(']')[0];
if (resultCode == 'FAIL') {
var err_code_des = util.getXMLNodeValue('err_code_des', res.data.toString("utf-8"));
var errDes = err_code_des.split('[')[2].split(']')[0];
wx.showToast({
title: errDes,
icon: 'none',
duration: 3000
})
} else {
//发起支付
var prepay_id = util.getXMLNodeValue('prepay_id', res.data.toString("utf-8"));
var tmp = prepay_id.split('[');
var tmp1 = tmp[2].split(']');
//签名
var key = '';//商户key必填,在商户后台获得
var appId = '';//appid必填
var timeStamp = util.createTimeStamp();
var nonceStr = util.randomString();
var stringSignTemp = "appId=" + appId + "&nonceStr=" + nonceStr + "&package=prepay_id=" + tmp1[0] + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + key;
console.log("签名字符串", stringSignTemp);
var sign = md5.md5(stringSignTemp).toUpperCase();
console.log("签名", sign);
var param = { "timeStamp": timeStamp, "package": 'prepay_id=' + tmp1[0], "paySign": sign, "signType": "MD5", "nonceStr": nonceStr }
console.log("param小程序支付接口参数", param);
that.processPay(param);
}
},
})
},
/* 小程序支付 */
processPay: function (param) {
wx.requestPayment({
timeStamp: param.timeStamp,
nonceStr: param.nonceStr,
package: param.package,
signType: param.signType,
paySign: param.paySign,
success: function (res) {
console.log("wx.requestPayment返回信息",res);
wx.showModal({
title: '支付成功',
content: '官方号中收到支付凭证',
showCancel: false,
success: function (res) {
if (res.confirm) {
} else if (res.cancel) {
}
}
})
},
fail: function () {
console.log("支付失败");
},
complete: function () {
console.log("支付完成");
}
})
}
客户端js
wx.request({
url:'',
header:{
'Content-Type':'application/x-www-form-urlencoded'
},
method:'POST',
success:function(res){
console.log(res.data);
console.log('调起支付');
wx.requestPayment({
'timeStamp': res.data.timeStamp,
'nonceStr': res.data.nonceStr,
'package': res.data.package,
'signType':'MD5',
'paySign': res.data.paySign,
'success':function(res){
console.log('success');
wx.showToast({
title:'支付成功',
icon:'success',
duration:3000
});
},
'fail':function(res){
console.log('fail');
},
'complete':function(res){
console.log('complete');
}
});
},
fail:function(res){
console.log(res.data)
}
});
先开通微信支付商户
在小程序后台,点击微信支付,申请开通,选择新申请,
统一下单:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
接口链接URL
地址:https://api.mch.weixin.qq.com/pay/unifiedorder
图片说明
举例如下:
<xml>
<appid>wx2421b1c4370ec43b</appid>
<attach>支付测试</attach>
<body>JSAPI支付测试</body>
<mch_id>10000100</mch_id>
<detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
<nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
<notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
<openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
<out_trade_no>1415659990</out_trade_no>
<spbill_create_ip>14.23.150.211</spbill_create_ip>
<total_fee>1</total_fee>
<trade_type>JSAPI</trade_type>
<sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>
微信支付的流程:
获取用户
code
值获取用户
openid
服务器上请求微信的统一下单接口,获取
prepay_id
值
微信支付的整个流程:
获取用户的code
值,请求用户的openid
.
//app.js
App({
onLaunch: function() {
wx.login({
success: function(res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
}
})
接着服务端来请求微信的地址:(参考微信官方api
)
https://api.weixin.qq.com/sns/jscode2session
public Map<String,Object> onLogin(String code){
Map<String,Object>result=new HashMap<>();
String url=ConstantUtils.getSessionKeyUrl+"?appid="+ ConstantUtils.appId+
"&secret="+ConstantUtils.secret+"&js_code="+code+"&grant_type="+ConstantUtils.grantType;
JSONObject httpResult=HttpUtils.httpGet(url);
result.put("openid",httpResult.get("openid"));
result.put("session_key",httpResult.get("session_key"));
result.put("expires_in",httpResult.get("expires_in"));
return result;
}
统一下单的接口,获取prepay_id
字段值
https://api.mch.weixin.qq.com/pay/unifiedorder
public Map<String,Object> createOrder(String openId){
Map<String,Object>result=new HashMap<>();
result.put("status","1");
result.put("payType","weixin");
result.put("orderId","123456");
String formData=orderService.commitData(openId);
String httpResult = HttpUtils.httpXMLPost(ConstantUtils.createOrderUrl,formData);
try {
Map<String, String> resultMap = WXPayUtil.xmlToMap(httpResult);
result.put("package", "prepay_id=" + resultMap.get("prepay_id"));
result.put("nonceStr",resultMap.get("nonce_str"));
} catch (Exception e) {
e.printStackTrace();
}
String times= WXPayUtil.getCurrentTimestamp()+"";
result.put("timeStamp",times);
Map<String, String> packageParams = new HashMap<String ,String>();
packageParams.put("appId", ConstantUtils.appId);
packageParams.put("signType", ConstantUtils.signType);
packageParams.put("nonceStr",result.get("nonceStr")+"");
packageParams.put("timeStamp",times);
packageParams.put("package", result.get("package")+"");//商户订单号
String sign="";
try {
sign= WXPayUtil.generateSignature(packageParams, ConstantUtils.key);
} catch (Exception e) {
e.printStackTrace();
}
result.put("paySign",sign);
return result;
}
WXPayUtil
工具类是微信官方demo
中的工具类.
可以JAVA
后台实现小程序支付
图片说明
调用支付统一下单API
来获取prepay_id
小程序调支付数据需要签名的字段appId
,timeStamp
,nonceStr
,package
再次签名.
微信公众平台支付接口调试工具
https://pay.weixin.qq.com/wiki/tools/signverify/
WXPayUtil.java
https://download.csdn.net/download/by965738071/10389430
代码
开通微信支付功能,需要商户号,appid
,appsecret
, openid
小程序:
参考
https://blog.csdn.net/fredrik/article/details/79697963
pay:function(){
var that=this
wx.getStorage({
key: 'openid',
success: function(res) {
wx.request({
url: url + 'Wx_Pay',
data: {
//用户的openid
openid:res.data,
fee: that.data.totalPrice, //支付金额
details: that.data.goodsList[0].goods_name,//支付商品的名称
},
success:function(result){
if(result.data){
wx.requestPayment({
timeStamp: result.data['timeStamp'],
nonceStr: result.data['nonceStr'],
package: result.data['package'],
signType: 'MD5',
paySign: result.data['paySign'],
'success':function(successret){
console.log('支付成功');
//获取支付用户的信息
wx.getStorage({
key: 'userInfo',
success: function (getuser) {
wx.request({
url: url + 'Wx_AddOrder',
data: {
uname: getuser.data.nickName,
goods: that.data.goodsList[0].goods_name,
price: that.data.totalPrice,
openid:res.data,
},
success: function (lastreturn) {
console.log("存取成功");
}
})
},
})
},'fail':function(res){
}
})
}
}
})
},
})
},
支付实现
图片说明
图片说明
图片说明
图片说明
小程序端代码:
wx.requestPayment({
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){
},
'fail':function(res){
}
})
小程序端代码如下:
pay:function(_payInfo,success,fail){
var payInfo = {
body:'',
total_fee:0,
order_sn:''
}
Object.assign(payInfo, _payInfo);
if(payInfo.body.length==0){
wx.showToast({
title:'信息描述错误'
})
return false;
}
if(payInfo.total_fee==0){
wx.showToast({
title:'金额不能0'
})
return false;
}
if(payInfo.order_sn.length==0){
wx.showToast({
title:'订单号不能为空'
})
return false;
}
var This = this;
This.getOpenid(function(openid){
payInfo.openid=openid;
This.request({
url:'api/pay/prepay',
data:payInfo,
success:function(res){
var data = res.data;
console.log(data);
if(!data.status){
wx.showToast({
title:data['errmsg']
})
return false;
}
This.request({
url:'api/pay/pay',
data:{prepay_id:data.data.data.prepay_id},
success:function(_payResult){
var payResult = _payResult.data;
console.log(payResult);
wx.requestPayment({
'timeStamp': payResult.timeStamp.toString(),
'nonceStr': payResult.nonceStr,
'package': payResult.package,
'signType': payResult.signType,
'paySign': payResult.paySign,
'success': function (succ) {
success&&success(succ);
},
'fail': function (err) {
fail&&fail(err);
},
'complete': function (comp) {
}
})
}
})
}
})
})
}
开通微信支付和微信商户号
获得用户的openid
wx.login({
success: function(res) {
if (res.code) {
wx.request({
url: 'https://yourwebsit/onLogin',
method: 'POST',
data: {
code: res.code
},
success: function(res) {
var openid = res.data.openid;
},
fail: function(err) {
console.log(err)
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
var code = req.param("code");
request({
url: "https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code",
method: 'GET'
}, function(err, response, body) {
if (!err && response.statusCode == 200) {
res.json(JSON.parse(body));
}
});
获取prepay_id
和支付签名验证paySign
图片说明
通过
wx.requestPayment
方法来调起支付功能
图片说明
prepay_id
的获取和签名paySign
,是从小程序请求后台来的.
图片说明
第一步:调用wx.login(object)
获取用户的code
,code
换取session_key
,
微信的第三个接口,统一下单,获取prepay_id
,第四个接口,wx.requestPayment(object)
,成功后,请求支付后的结果.
先执行wx.login
小程序代码:
<view>
<button bindtap='wxpay' class='css'>发起支付</button>
</view>
// js
var app=getApp();
Page({
wxpay: function(){
var code=app.code;
wx.request({
url: SERVER_PATH+'wxpayapi/,
data: {
code: code
},
header: {
'content-type': 'application/json'
},
success: function (res) {
console.log(res.data);
var data=res.data;
wx.requestPayment({
'timeStamp': data.timeStamp,
'nonceStr': data.nonceStr,
'package': data.package,
'signType': 'MD5',
'paySign': data.paySign,
'success': function (res) {
console.log("支付成功!")
},
'fail': function (res) {
}
})
}
})
}
})
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
图片说明
实例参考地址:
https://pan.baidu.com/s/1pKLgG8z
https://pan.baidu.com/s/1nuBH0EX
达叔小生:往后余生,唯独有你
You and me, we are family !
90后帅气小伙,良好的开发习惯;独立思考的能力;主动并且善于沟通
简书博客: 达叔小生
https://www.jianshu.com/u/c785ece603d1
结语
下面我将继续对 其他知识 深入讲解 ,有兴趣可以继续关注
小礼物走一走 or 点赞
这是一个有质量,有态度的公众号
喜欢本文的朋友们
欢迎长按下图关注订阅号
收看更多精彩内容