背景:
在Web應用中接入微信支付,我以為只是調用幾個API稍作調試即可。
沒想到微信的API和官方文檔里隱坑無數,致我抱着懷疑人生的心情悲憤踩遍了丫們布下的所有坑。
簡要介紹幾個主要大坑:
坑一:關於WeixinJSBridge這個對象
查閱網頁端調起支付API的開發文檔,此對象即旁若無人的映入眼簾。
然后我們就理所應當的在代碼里調用了丫的。
可是,too young too naive……
盡管此對象只在微信瀏覽器里有效,借此可判斷用戶是否在微信瀏覽器里訪問應用。
但其實調用了丫之后,你是沒有未來的……
此坑所耗時間:1.5天。
坑二:幾個簽名的混淆
關於簽名的調試,網上各種哭嚎,不少人在簽名處調試多日無果。
那是因為整個工作流程中,涉及到了至少三個簽名,稍不小心就會用錯。
在統一下單的接口里,向微信服務器發送請求中的參數有一枚簽名;
其返回的參數中,亦有一枚簽名,后經觀察,發現二者為同一簽名。
但在使用JSSDK后所調用的wx.config里所需的參數signature卻是另一枚簽名。
而在wx.chooseWXPay里所需的支付簽名paySign,卻又是另另另外的一枚。
此坑所耗時間:2天。
坑三:兩個Access_token
查看開發文檔可以看到,微信搞了兩個Access_token!
即使他們用再多的加粗文字來提醒我們兩個token的不同之處,
也難以撫平我們在開發過程中陷入混亂的受傷之身心!
一個是網頁授權的access_token,需要用戶授權之后才能拿到。
而另一個是普通的access_token,支持公眾號的各種基礎服務,並非支付獨用。
看文檔所述的流程,以為用網頁授權的token就對了?
恭喜,又進坑了……
最后真正用到的是第二個token。
此坑所耗時間:1.5天。
…………
坑坑相套,防不勝防。最終跑通功能后,心力交瘁矣!
為防以后再次進坑,在此總結一番,供各位參考。
背景畢。
———————————————— 我是悲憤不已的分割線 ————————————————
准備工作第一彈:
公眾號一枚,並開通微信支付功能。
在微信公眾平台(mp.weixin.qq.com)的[微信支付-開發配置]里對支付授權目錄做配置。
測試期間,需要配置測試授權目錄,以及將參與測試的微信號添加到白名單中。
由於測試必須在線上(測試)環境,debug不太方便,才耗費了辣么多美好的時光。
授權目錄,即為調用微信支付控件的頁面所在目錄。
准備工作第二彈:
還是在公眾平台上,進入開發者中心,找到接口權限表。
在其中的網頁服務中,找到“網頁授權用戶基本信息”並填寫之。
這里所填的URL必須是用戶進入應用的URL,且必須是oauth驗證所用的URL里的redirect_uri里的值……
一處不對,都會在坑里苦熬良久。
准備工作第三彈:
還是在公眾平台上,進入公眾號設置,找到功能設置。
需要對JS接口安全域名做設置。
這里的安全域名就是你的應用相關的域名,改動次數受限制,要注意。
准備工作第四彈:
還是在公眾平台上,在開發者中心里找到配置項。
這里需要有APPID和APPSecret的訪問權限。
另外,還需要准備的是商戶id:mch_id 和 key。
注:secret 和 key 在通信接口里有用到,不允許在前端頁面使用!
———————————————— 我是躍躍欲試的分割線 ————————————————
第一步驟:一個帶驗證的入口URI
首先引導用戶進入應用,這里以H5頁面為例。
由於微信支付必須在微信瀏覽器里進行,因此入口URL鏈接應當從公眾號發布給用戶,
這樣用戶才會在微信客戶端中點擊鏈接,進入應用。
(不要問京東為什么可以在純網頁端使用微信支付,那是微信給他的小伙伴京東開的后門好嗎)
這個入口URL不是簡單的URL,這里需要做oauth的驗證,因此我們暫設此URL為entranceURL。
entranceURL的格式為:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
標紅的幾個變量需要說明:
1. APPID就是公眾號的appid
2. REDIRECT_URI很眼熟?就是剛在網頁授權里寫的URI,要轉義哦親。
3. response_type須填code,理由是這是一個GET請求,微信會返回code然后用code再……blah blah blah
4. SCOPE,填snsapi_userinfo(需用戶手動授權)或snsapi_base(直接進入頁面)
5. STATE 會跟隨code一起返回,看業務需要自己填。一般格式是有大小寫和數字的組合。
第二步驟:用code獲取openId
用戶點擊了這個entranceURL之后會發生什么奇妙的事情咩?
這時候微信會返回給你一個code,並重定向到你在REDIRECT_URI里指定的頁面。
你需要在這個頁面的URL里拿到code的值,如果拿不到,要提示用戶授權失敗或未授權。
由於這個entranceURL可能是應用的首頁,而需要調用支付控件的是其他頁面,
所以可以先將其緩存到例如sessionStorage里,到了需要調用支付控件時再用。
拿到這個code需要做什么咩?
這時候要做的事情就不能在前端頁面里繼續進行了,這里必須寫一個前后端通信的接口,
將這個code傳送給后端服務器,然后在服務器里發起對微信的GET請求:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=我的appid&secret=我的secret&code=這個code&grant_type=authorization_code;
標紅的是需要被替換的變量,其中appid和secret都應該保存在服務端文件中。
這個請求返回的Json里的openid就是我們要的。
第三步驟:統一下單接口
接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
參考文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
這個接口在文檔里講得很清楚,在此不贅述。
注意這里有簽名sign,它與后面要用的signature和paySign雖然都是簽名,但完全不同。
如果你的trade_type是NATIVE就不需要openid,如果是JSAPI就必須要openid。
在統一下單的接口中,你會告訴微信當前這筆交易的一些基本信息,
包括但不限於商戶id、交易號、交易金額等等。
微信會將其打包到一個package里,從接口返回的prepay_id里其實就對應了你的交易詳情。
注意這個接口返回的狀態碼有兩種,一個標識的是通信是否成功:return_code
另一個標識的是業務是否成功:result_code。詳情見文檔。
第四步驟:前端配置wx.config
在上一步接口的業務返回成功之后,可以在前端引用JSSDK了。
開發文檔在:https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
首先注入權限驗證配置時,需要用到wx.config。
它有幾個參數要格外注意,不然又進坑了:
1. 隨機字符串nonceStr,必須使用上一步的統一下單接口返回的nonceStr。
2. 簽名signature,不是上步接口里的sign,需在服務端生成,返給前端。(見下一步驟)
3. jsApiList 里要指定微信支付接口“chooseWXPay”。
4. debug參數設為true時,會在移動端打出alert幫助調試。
第五步驟:服務端生成wx.config所需的signature
首先用appid和secret從微信基礎支持接口中獲取access_token。
前面提到了兩個token:網頁授權型token和普通型token。
這里獲取的是普通型token。
由於這個token是公眾號所有服務都可能用到的,因此要格外注意。
有效期7200s,建議過期之前應當緩存之。
然后用這個token去獲取jsapi_ticket,接口地址:
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+ access_token +"&type=jsapi
這個ticket同樣也要做緩存。
現在可以准備生成signature了,所需的參數有:
1. jsapi_ticket
2. nonceStr 即統一下單接口返回的隨機字符串
3. 時間戳:秒為單位(后續還會用到時間戳,要保持一致)
4. 當前頁面URL,不需轉義
注意這個簽名是用sha1算法加密,其他的簽名是用MD5算法加密的。
第六步驟:終於開始配置chooseWXPay了
wx.config的驗證通過之后,就可以在wx.ready的回調里執行wx.chooseWXPay了。
chooseWXPay的幾個屬性配置說明如下:
1. timeStamp:剛才用到的那個時間戳,秒為單位。
2. nonceStr:統一下單接口里的隨機字符串
3. package:值的格式為“prepay_id=”+統一下單接口返回的prepay_id
4. signType:由於這里的簽名是MD5加密,因此這個值就是“MD5”
5. paySign:呵呵,此處是坑,這個簽名也是在服務端生成,返給前端,見下一步驟。
6. success:支付成功后的回調。
7. fail: 支付失敗后的回調。
8. cancel:用戶取消支付后的回調。
這里注意,由於進入應用時是帶着oauth驗證的,因此在用戶取消支付后,
code可能已過期,因此建議在取消支付的回調里,調用wx.closeWindow()退出Web頁返回微信客戶端。
因為即使你不退出,再執行支付,code之后的驗證也不會通過。
這時只能重新訪問一次第一步驟中的entranceURL才行。
第七步驟:生成chooseWXPay所需的簽名paySign
這個簽名不同於剛才在wx.config里的簽名signature,這是用MD5加密的。
生成簽名所需參數有appid,nonceStr,package,signType和timeStamp。(字典序排列)
其中nonceStr和package都是前面調用的統一下單的接口返回的。
這里的signType是“MD5”.
另外,這個簽名拼合的時候,最后要加一個key,就是app的key。
key的排序在最后,排序不參與字典序。具體規則見官方文檔。
第八步驟:測試
至此,萬事具備,包括東風。可以測試了。
建議使用iPhone手機測試,如果有問題IOS會報出錯信息,Android不會。
最常見的問題就是“Invalid signature”,這個錯誤信息太籠統了。
需要更細致的調試和辛勤的打Log。我在這個坑里淌了兩天……
注:本地測試環境不能測試,必須發布到線上測試環境(非生產環境),
並且線上測試環境的域名和URI等信息都要在公眾號設置里有授權。
———————————————— 我是蠢蠢欲動的分割線 ————————————————
如此看來,流程清晰多了,也無甚難處。
可當初做開發和調試時,因為對后端語言不熟,耗費了很多時間,
用JS三秒寫出的方法,用后端語言寫就頻繁報錯,
什么也不說了,只恨自己讀書少。
最后感謝在此過程中提供語法指點的盆友。