微信支付開發(fā)經(jīng)歷 - 坑爹的微信

嘮叨幾句

因為被微信那個破爛文檔坑了我兩個星期,導(dǎo)致項目進度慢了很多。本來微信的 API 的確是設(shè)計得爛,但爛我也覺得不要緊了,文檔也爛那我就真的火了,跟人捉迷藏似的東一塊西一塊(玩猜謎嗎你)。這里也記錄一下我做開發(fā)遇到的坑。

如何申請公眾號以及商戶平臺不在本文范疇內(nèi),因為項目經(jīng)理已經(jīng)拿到這這些東西了,我所做的就是完成代碼的編寫。

環(huán)境

這里使用了 com.github.binarywang 的 jar,下面默認都是在這個前期下討論。其他自己實現(xiàn)的或者其他人的庫請配合文檔和其他人分享的資料看。

<dependency>
  <groupId>com.github.binarywang</groupId>
  <artifactId>weixin-java-mp</artifactId>
  <version>2.8.0</version>
</dependency>

<dependency>
  <groupId>com.github.binarywang</groupId>
  <artifactId>weixin-java-pay</artifactId>
  <version>2.8.0</version>
</dependency>

正文

首先有一個十分重要的提醒:

配合前端開發(fā)人員測試微信支付的時候千萬千萬不能用微信的沙箱。

那個沙箱沒有他們文檔說的那么厲害,只能確認微信回調(diào)我們服務(wù)器沒問題,不能用來模擬測試整個支付流程,而且這個沙箱設(shè)計得十分垃圾,連沙箱都算不上(支付金額只允許用例內(nèi)的。你見過只能畫指定幾個圖案的沙箱嗎??),所以還是乖乖地測一次給一分錢吧。

開發(fā)

一般開發(fā)主要用到微信的兩種支付方式

  • JSAPI : 用于在微信自己的瀏覽器里面喚起微信支付
  • NATIVE : 用于掃碼支付

JSAPI 不用多說,就是觸發(fā)之后會喚起微信的支付對話框給用戶選擇支付與否。

NATIVE 就是生成訂單之后給用戶用微信掃碼付款的。這個方式我看了文檔,微信給本來的設(shè)計貌似是給那些自動販賣機用的,不過稍微改變一下使用方法就可以適用于任意掃碼支付。

JSAPI 和 NATIVE 兩種支付方式均使用統(tǒng)一下單接口先獲取微信預(yù)付款訂單信息,然后再進行剩下的操作。兩者傳參幾乎一樣,不同的是:

  • JSAPI 需要傳入 openId,NATIVE 不需要。
  • NATIVE 需要傳入 productId,JSAPI 不需要。

上面所說的稍微改變一下使用方法,就是在 NATIVE 支付的時候 productId 使用自己的訂單 ID 就好了。

NATIVE 支付方式

首先說這個支付方式是因為,這個方式很簡單,而且我也很推薦用這個,但掃碼就需要用另外一臺手機了。

根據(jù)微信的文檔向統(tǒng)一下單接口傳入相應(yīng)的參數(shù)之后,就得到預(yù)付款訂單了。這里得到的預(yù)付款訂單包含了參數(shù) codeUrl ,傳這個給前端開發(fā)的去生成二維碼或者自己服務(wù)器端生成二維碼都可以,掃碼之后就可以用微信付款。付款成功之后,微信會通過預(yù)先指定的回調(diào) API 發(fā)送訂單支付的結(jié)果。根據(jù)結(jié)果完成自己的訂單邏輯這個就不說了。

JSAPI 支付方式

我覺得這個就是最坑爹的地方了。

首先傳入?yún)?shù)之后,微信返回了預(yù)付款訂單信息,然后這個信息需要返回給前端。但是,這之前需要對預(yù)付款訂單的某些字段拼接起來,作一次簽名,簽名需要嚴格按照字段序排序以及注意大小寫:

  • appId
  • nonceStr
  • package
  • signType
  • timeStamp
StringBuilder params = new StringBuilder()
    .append("appId=").append(wxPayService.getConfig().getAppId()).append("&")
    .append("nonceStr=").append(nonceStr).append("&")
    .append("package=").append("prepay_id=").append(orderResult.getPrepayId()).append("&")
    .append("signType=").append("MD5").append("&")
    .append("timeStamp=").append(timestamp);
//appId={appId}&nonceStr={nonceStr}&package=prepay_id={prepayId}&signType=MD5&timeStamp={timestamp}

(真心對微信大小寫隨便來表示很無語)其中

  • nonceStr
  • prepay_id

需要與微信返回的預(yù)付款訂單內(nèi)的一致。timeStamp 也要傳給前端,到時候前端需要把這個 timeStamp 傳進喚起微信支付對話框的函數(shù)。

拼接好這個之后,再在后面拼接參數(shù) key 并進行一次 MD5。

params.append("&").append("key=").append(wxPayService.getConfig().getMchKey());
String prepay_sign = DigestUtils.getMD5(true, params.toString());

所以所需要傳給前端的參數(shù)如下:

{
  "appId":"你的 appId",
  "nonceStr":"訂單內(nèi)的 nonceStr",
  "timeStamp":"訂單參數(shù)簽名的時間",
  "prepay_sign":"訂單簽名結(jié)果"
}

這時候不要急著去喚起微信的支付窗口,因為還有后面一系列步驟。

這里需要注意這些返回的參數(shù):

  • nonceStr
  • timeStamp

這兩個參數(shù)在整個支付的過程中要一致,而且參數(shù)大小寫也需要注意。流程內(nèi)的 API 有的地方給弄駝峰命名法有的地方則用全小寫。

然后,前端需要再拿當(dāng)前調(diào)用 JSAPI 支付的瀏覽器地址欄的路徑,向服務(wù)器請求一個簽名,這個簽名就是前端喚起 JSAPI 所需要的簽名,我這里請求的 API 以及示例如下:

POST -> https://shinonometn.com/WC/ticket

{
  "url":"https://shinonometn.com/?#/order/11",
  "nonceStr":"8897djsk09ll",
  "timeStamp":1560789
}

url 那里一定一定要注意,對于 SPA 應(yīng)用,路由前綴那里,絕對不能只有一個#,微信的這個安全機制很傻屄。首先你需要去商戶平臺那里注冊 JSAPI 支付允許的“支付目錄”(我暈,目錄),然后在調(diào)用 JSAPI 支付的時候他們會校驗?zāi)愕刂窓凇痹凇安弧痹凇耙炎缘摹爸Ц赌夸洝保辉诰途芙^下單。我猜他們這個機制是做給服務(wù)器端渲染頁面的應(yīng)用做的:你會發(fā)現(xiàn)你的 SPA 應(yīng)用拿到的 URL 經(jīng)常跟他們微信拿到的 URL 不匹配,從而一直提示你 URL 未注冊 然后拒絕下單。這其實不算坑,文檔在很隱蔽的地方提及需要前端拿這個 sign 去調(diào)用 JSAPI 支付 and 支付前需要調(diào)用 config 一次才是坑死人。

這個簽名是這樣的,如下參數(shù)全小寫,嚴格按照字典順序排序:

  • jsapi_ticket(我一直不知道這個東西的存在,因為文檔里面沒有提及)
  • noncestr(小寫,小心)
  • timestamp (小寫,小心)
  • url (就是上面提及的 URL)

然后如此拼接:

jsapi_ticket={你拿到的 JSAPI TICKET}&noncestr={訂單上的 nonceStr}&timestamp={你訂單的 timeStamp}&url={URL}

//不算大括號,只是為了好看加上去的

然后對這這個拼接好的字符串,SHA1 一次,拿小寫的字符串,返回給前端,那么前端就可以很愉快地填上對應(yīng)的參數(shù)去 wx.config 一下,喚起微信支付窗口了。

那么這個 URL 在商戶平臺注冊的時候需要注意什么呢?對于服務(wù)器端渲染頁面,你需要填寫支付頁面的地址,刪掉最后的”目錄“:

//訂單支付頁面
https://shinonometn.com/order/pay/1
//注冊的 URL
https://shinonometn.com/order/pay/

對于 SPA (單頁應(yīng)用)來說,你只需要填寫你的應(yīng)用地址,路由那里怎么方便怎么做手腳。

//帶上路由的 SPA 的頁面
https://shinonometn.com/?#/order/pay/1
                        ^我就弄了個問號
//注冊的 URL
https://shinonometn.com/

唉,就是因為 JSAPI 的沙雕設(shè)計我加班到凌晨 2 點陪前端的人調(diào)試。

參考鏈接

在Web應(yīng)用中接入微信支付的流程之極簡清晰
微信開發(fā),分享部分出現(xiàn)的問題
微信支付:“當(dāng)前頁面的URL未注冊”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容