微信JSAPI支付操作需要注意的細(xì)節(jié)
首先介紹一下我在調(diào)用微信支付接口使用的是 weixin.senparc SDK,非常方便好用開源的一個(gè)微信開發(fā)SDK。
weixin.senparc SDK 官網(wǎng):http://weixin.senparc.com/
先去下載下來(lái)Senparc.Weixin SDK。
在調(diào)起支付接口之前,需要先要調(diào)用統(tǒng)一下單接口,商戶系統(tǒng)先調(diào)用該接口在微信支付服務(wù)后臺(tái)生成預(yù)支付交易單,返回正確的預(yù)支付交易回話標(biāo)識(shí)后再在APP里面調(diào)起支付。
微信 JsApi支付 在這個(gè)目錄下 Senparc.Weixin.MP.Sample.Controllers 找到JsApi支付。
public ActionResult JsApi(string code, string state) { if (string.IsNullOrEmpty(code)) { return Content("您拒絕了授權(quán)!"); } if (!state.Contains("|")) { //這里的state其實(shí)是會(huì)暴露給客戶端的,驗(yàn)證能力很弱,這里只是演示一下 //實(shí)際上可以存任何想傳遞的數(shù)據(jù),比如用戶ID,并且需要結(jié)合例如下面的Session["OAuthAccessToken"]進(jìn)行驗(yàn)證 return Content("驗(yàn)證失??!請(qǐng)從正規(guī)途徑進(jìn)入!1001"); } try { //獲取產(chǎn)品信息 var stateData = state.Split('|'); int productId = 0; ProductModel product = null; if (int.TryParse(stateData[0], out productId)) { int hc = 0; if (int.TryParse(stateData[1], out hc)) { var products = ProductModel.GetFakeProductList(); product = products.FirstOrDefault(z => z.Id == productId); if (product == null || product.GetHashCode() != hc) { return Content("商品信息不存在,或非法進(jìn)入!1002"); } ViewData["product"] = product; } } //通過(guò),用code換取access_token var openIdResult = OAuthApi.GetAccessToken(TenPayV3Info.AppId, TenPayV3Info.AppSecret, code); if (openIdResult.errcode != ReturnCode.請(qǐng)求成功) { return Content("錯(cuò)誤:" + openIdResult.errmsg); } string sp_billno = Request["order_no"]; if (string.IsNullOrEmpty(sp_billno)) { //生成訂單10位序列號(hào),此處用時(shí)間和隨機(jī)數(shù)生成,商戶根據(jù)自己調(diào)整,保證唯一 sp_billno = string.Format("{0}{1}{2}", TenPayV3Info.MchId, DateTime.Now.ToString("yyyyMMdd"), TenPayV3Util.BuildRandomStr(10)); } else { sp_billno = Request["order_no"]; } var timeStamp = TenPayV3Util.GetTimestamp(); var nonceStr = TenPayV3Util.GetNoncestr(); var body = product == null ? "test" : product.Name; var price = product == null ? 100 : product.Price * 100; var xmlDataInfo = new TenPayV3UnifiedorderRequestData(TenPayV3Info.AppId, TenPayV3Info.MchId, body, sp_billno, price, Request.UserHostAddress, TenPayV3Info.TenPayV3Notify, TenPayV3Type.JSAPI, openIdResult.openid, TenPayV3Info.Key, nonceStr); var result = TenPayV3.Unifiedorder(xmlDataInfo);//調(diào)用統(tǒng)一訂單接口 //JsSdkUiPackage jsPackage = new JsSdkUiPackage(TenPayV3Info.AppId, timeStamp, nonceStr,); var package = string.Format("prepay_id={0}", result.prepay_id); ViewData["appId"] = TenPayV3Info.AppId; ViewData["timeStamp"] = timeStamp; ViewData["nonceStr"] = nonceStr; ViewData["package"] = package; ViewData["paySign"] = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key); return View(); } catch (Exception ex) { var msg = ex.Message; msg += "<br>" + ex.StackTrace; msg += "<br>==Source==<br>" + ex.Source; if (ex.InnerException != null) { msg += "<br>===InnerException===<br>" + ex.InnerException.Message; } return Content(msg); } }
先在微信服務(wù)后臺(tái)生成預(yù)支付交易單,獲得預(yù)支付訂單號(hào)。
先說(shuō)說(shuō)在統(tǒng)一下單這里遇到的坑。
1.在統(tǒng)一下單的時(shí)候解析返回結(jié)果,一直出現(xiàn)以下問(wèn)題:您沒有JSAPI支付權(quán)限
<xml> <return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[您沒有JSAPI支付權(quán)限]]></return_msg> </xml>
1)先看看你的公眾號(hào)微信支付設(shè)置是否正確。
關(guān)于如何配置微信支付:可以參考這個(gè) http://jingyan.baidu.com/article/77b8dc7fef360d6174eab690.html
2)檢查你的授權(quán)目錄是否正確,格式要這樣,后面記得別漏了一個(gè)/ 例如:http://test.cn/u/
3)檢查需要傳過(guò)去的賬戶參數(shù),上公眾號(hào)還有商戶號(hào)檢查你的賬戶參數(shù)是否正確。我在開發(fā)當(dāng)中就出現(xiàn),微信公眾號(hào)商戶號(hào),appid 是分別不同兩個(gè)公眾號(hào)的,坑啊,找了好久,覺得不對(duì)勁,原來(lái)是給的配置參數(shù)密鑰不對(duì)。
這里詳細(xì)說(shuō)一下對(duì)應(yīng)的參數(shù):
MCHID:商戶號(hào)(必須配置,開戶郵件中可查看),商戶申請(qǐng)微信支付后,由微信支付分配的商戶收款賬號(hào)。
APPID:微信開放平臺(tái)審核通過(guò)的應(yīng)用APPID,appid是微信公眾賬號(hào)或開放平臺(tái)APP的唯一標(biāo)識(shí),在公眾平臺(tái)申請(qǐng)公眾賬號(hào)或者在開放平臺(tái)申請(qǐng)APP賬號(hào)后,微信會(huì)自動(dòng)分配對(duì)應(yīng)的appid用于標(biāo)識(shí)該應(yīng)用??稍谖⑿殴娖脚_(tái)-->開發(fā)者中心查看,商戶的微信支付審核通過(guò)郵件中也會(huì)包含該字段值.
KEY:商戶支付密鑰,參考開戶郵件設(shè)置(必須配置,登錄商戶平臺(tái)自行設(shè)置),交易過(guò)程生成簽名的密鑰,僅保留在商戶系統(tǒng)和微信支付后臺(tái),不會(huì)在網(wǎng)絡(luò)中傳播。商戶妥善保管該Key,切勿在網(wǎng)絡(luò)中傳輸,不能在其他客戶端中存儲(chǔ),保證key不會(huì)被泄漏。商戶可根據(jù)郵件提示登錄微信商戶平臺(tái)進(jìn)行設(shè)置。也可按一下路徑設(shè)置:微信商戶平臺(tái)(pay.weixin.qq.com)-->賬戶設(shè)置-->API安全-->密鑰設(shè)置.
APPSECRET:公眾帳號(hào)secert(僅JSAPI支付的時(shí)候需要配置, 登錄公眾平臺(tái),進(jìn)入開發(fā)者中心可設(shè)置)
2.在統(tǒng)一下單,解析返回來(lái)的結(jié)果我出現(xiàn)了商戶號(hào)mch_id與appid不匹配這個(gè)問(wèn)題
<xml> <return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[商戶號(hào)mch_id與appid不匹配]]></return_msg> </xml>
原因是我拿到的商戶號(hào)不是這個(gè)公眾號(hào)的。一定要檢查是不是這個(gè)公眾號(hào)的商戶號(hào)。
3.在統(tǒng)一下單,解析返回來(lái)的結(jié)果出現(xiàn) appid and openid not match,appid和openid不匹配。
<xml> <return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[appid and openid not match]]></return_msg> </xml>
原因是我這個(gè)用戶的openid 不是這個(gè)公眾號(hào)的
4.在統(tǒng)一下單,解析返回來(lái)的結(jié)果出現(xiàn) CDATA[openid is invalid],openid無(wú)效
<xml> <return_code><![CDATA[FAIL]]></return_code> <return_msg><![CDATA[openid is invalid]]></return_msg> </xml>
原因是,傳過(guò)去不是有效的opendid。不小心看錯(cuò)了,把用戶id 當(dāng)做openid傳過(guò)去了。
當(dāng)統(tǒng)一下單成功,會(huì)返回以下格式的參數(shù)
<xml> <return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg> <appid><![CDATA[wx2421b1c4370ec43b]]></appid> <mch_id><![CDATA[10000100]]></mch_id> <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str> <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign> <result_code><![CDATA[SUCCESS]]></result_code> <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id> <trade_type><![CDATA[APP]]></trade_type> </xml>
解析獲得預(yù)支付單號(hào):
string prepayId = res.Element("xml").Element("prepay_id").Value; //獲取預(yù)支付訂單號(hào)
給頁(yè)面對(duì)應(yīng)地參數(shù)
ViewData["appId"] = TenPayV3Info.AppId; ViewData["timeStamp"] = timeStamp; ViewData["nonceStr"] = nonceStr; ViewData["package"] = package; ViewData["paySign"] = TenPayV3.GetJsPaySign(TenPayV3Info.AppId, timeStamp, nonceStr, package, TenPayV3Info.Key);
靜態(tài)頁(yè)面js調(diào)用:
wx.chooseWXPay({ timestamp: 0, // 支付簽名時(shí)間戳,注意微信jssdk中的所有使用timestamp字段均為小寫。但最新版的支付后臺(tái)生成簽名使用的timeStamp字段名需大寫其中的S字符 nonceStr: '', // 支付簽名隨機(jī)串,不長(zhǎng)于 32 位 package: '', // 統(tǒng)一支付接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=***) signType: '', // 簽名方式,默認(rèn)為'SHA1',使用新版支付需傳入'MD5' paySign: '', // 支付簽名 success: function (res) { if (res.err_msg == "get_brand_wcpay_request:ok") {//支付成功 } else { //支付失敗 } // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對(duì)可靠。 } });
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS自定義對(duì)象實(shí)現(xiàn)Java中Map對(duì)象功能的方法
這篇文章主要介紹了JS自定義對(duì)象實(shí)現(xiàn)Java中Map對(duì)象功能的方法,可實(shí)現(xiàn)類似Java中Map對(duì)象增刪改查等功能,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01JavaScript隊(duì)列數(shù)據(jù)結(jié)構(gòu)詳解
這篇文章主要介紹了JavaScript隊(duì)列數(shù)據(jù)結(jié)構(gòu)詳解,隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),隊(duì)列中允許兩種基礎(chǔ)操作,也就是插入和刪除,也就是入隊(duì)和出隊(duì)2022-07-07JavaScript中Set和Map數(shù)據(jù)結(jié)構(gòu)使用場(chǎng)景詳解
這篇文章主要為大家介紹了JavaScript中Set和Map數(shù)據(jù)結(jié)構(gòu)使用場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06IE7中javascript操作CheckBox的checked=true不打勾的解決方法
在IE7下,生成的Checkbox無(wú)法正確的打上勾。 原因是 chkbox控件還沒初始化(appendChild),就開始操作它的結(jié)果2009-12-12微信小程序基于ColorUI構(gòu)建皮皮蝦短視頻去水印組件
這篇文章主要介紹了微信小程序-基于ColorUI構(gòu)建皮皮蝦短視頻去水印組件,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-11-11JavaScript實(shí)現(xiàn)將Word文檔解析成瀏覽器認(rèn)識(shí)的HTML
這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript實(shí)現(xiàn)將Word文檔解析成瀏覽器認(rèn)識(shí)的HTML,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-02-02JavaScript String(字符串)對(duì)象的簡(jiǎn)單實(shí)例(推薦)
下面小編就為大家?guī)?lái)一篇JavaScript String(字符串)對(duì)象的簡(jiǎn)單實(shí)例(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08uni-app和web-view頁(yè)面相互傳參方法實(shí)例
web-view是一個(gè)web瀏覽器組件,可以用來(lái)承載網(wǎng)頁(yè)的容器,會(huì)自動(dòng)鋪滿整個(gè)頁(yè)面,下面這篇文章主要給大家介紹了關(guān)于uni-app和web-view頁(yè)面相互傳參的相關(guān)資料,需要的朋友可以參考下2023-06-06用javascript實(shí)現(xiàn)始終保持打開同一個(gè)子窗口以及關(guān)閉父窗口同時(shí)自動(dòng)關(guān)閉所有子窗口
用javascript實(shí)現(xiàn)始終保持打開同一個(gè)子窗口以及關(guān)閉父窗口同時(shí)自動(dòng)關(guān)閉所有子窗口...2007-06-06