微信小程序實現微信支付功能流程php
微信支付:css
https://pay.weixin.qq.com/wiki/doc/api/index.html
html
圖片說明java
進行選擇接入web
圖片說明算法
圖片說明json
步驟:小程序
小程序調用登陸接口,獲取用戶的openid
, wx.login(object)
, 經過調用接口獲取登陸憑證code
進行獲取登陸用戶信息,包含用戶的惟一標識(openid
)以及本次登陸的會話密鑰(session_key
).微信小程序
用code
獲取session_key
, 這是一個https
接口,開發者服務器使用登陸憑證code
獲取session_key
和openid
.其中session_key
是對用戶數據進行保密的密鑰.爲了安全,不能將session_key
在網絡上傳輸.api
圖片說明
獲取的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
參數 | 類型 | 必填 | 說明 |
---|---|---|---|
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
圖片說明
注意事項:
圖片說明
小程序支付的流程圖以下:
圖片說明
圖片說明
一、【[小程序登陸API](https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html?t=20161122)】
二、【[統一下單API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1)】
三、【[再次簽名](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3)】
四、【[支付結果通知API](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7)】
五、【[查詢訂單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
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(succe***et){ 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 點贊
這是一個有質量,有態度的公衆號
喜歡本文的朋友們
歡迎長按下圖關注訂閱號
收看更多精彩內容