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

嘮叨幾句

因?yàn)楸晃⑿拍莻€(gè)破爛文檔坑了我兩個(gè)星期报账,導(dǎo)致項(xiàng)目進(jìn)度慢了很多当宴。本來(lái)微信的 API 的確是設(shè)計(jì)得爛纵势,但爛我也覺(jué)得不要緊了踱阿,文檔也爛那我就真的火了,跟人捉迷藏似的東一塊西一塊(玩猜謎嗎你)钦铁。這里也記錄一下我做開(kāi)發(fā)遇到的坑软舌。

如何申請(qǐng)公眾號(hào)以及商戶(hù)平臺(tái)不在本文范疇內(nèi),因?yàn)轫?xiàng)目經(jīng)理已經(jīng)拿到這這些東西了牛曹,我所做的就是完成代碼的編寫(xiě)佛点。

環(huán)境

這里使用了 com.github.binarywang 的 jar,下面默認(rèn)都是在這個(gè)前期下討論黎比。其他自己實(shí)現(xiàn)的或者其他人的庫(kù)請(qǐng)配合文檔和其他人分享的資料看超营。

<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>

正文

首先有一個(gè)十分重要的提醒:

配合前端開(kāi)發(fā)人員測(cè)試微信支付的時(shí)候千萬(wàn)千萬(wàn)不能用微信的沙箱。

那個(gè)沙箱沒(méi)有他們文檔說(shuō)的那么厲害阅虫,只能確認(rèn)微信回調(diào)我們服務(wù)器沒(méi)問(wèn)題演闭,不能用來(lái)模擬測(cè)試整個(gè)支付流程,而且這個(gè)沙箱設(shè)計(jì)得十分垃圾颓帝,連沙箱都算不上(支付金額只允許用例內(nèi)的米碰。你見(jiàn)過(guò)只能畫(huà)指定幾個(gè)圖案的沙箱嗎?购城?)吕座,所以還是乖乖地測(cè)一次給一分錢(qián)吧。

開(kāi)發(fā)

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

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

JSAPI 不用多說(shuō)瘪板,就是觸發(fā)之后會(huì)喚起微信的支付對(duì)話(huà)框給用戶(hù)選擇支付與否吴趴。

NATIVE 就是生成訂單之后給用戶(hù)用微信掃碼付款的。這個(gè)方式我看了文檔侮攀,微信給本來(lái)的設(shè)計(jì)貌似是給那些自動(dòng)販賣(mài)機(jī)用的锣枝,不過(guò)稍微改變一下使用方法就可以適用于任意掃碼支付厢拭。

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

  • JSAPI 需要傳入 openId箭昵,NATIVE 不需要税朴。
  • NATIVE 需要傳入 productId,JSAPI 不需要家制。

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

NATIVE 支付方式

首先說(shuō)這個(gè)支付方式是因?yàn)椴梗@個(gè)方式很簡(jiǎn)單觅廓,而且我也很推薦用這個(gè),但掃碼就需要用另外一臺(tái)手機(jī)了涵但。

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

JSAPI 支付方式

我覺(jué)得這個(gè)就是最坑爹的地方了哨啃。

首先傳入?yún)?shù)之后烧栋,微信返回了預(yù)付款訂單信息,然后這個(gè)信息需要返回給前端拳球。但是审姓,這之前需要對(duì)預(yù)付款訂單的某些字段拼接起來(lái),作一次簽名祝峻,簽名需要嚴(yán)格按照字段序排序以及注意大小寫(xiě):

  • 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}

(真心對(duì)微信大小寫(xiě)隨便來(lái)表示很無(wú)語(yǔ))其中

  • nonceStr
  • prepay_id

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

拼接好這個(gè)之后画畅,再在后面拼接參數(shù) key 并進(jìn)行一次 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ù)簽名的時(shí)間",
  "prepay_sign":"訂單簽名結(jié)果"
}

這時(shí)候不要急著去喚起微信的支付窗口宋距,因?yàn)檫€有后面一系列步驟轴踱。

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

  • nonceStr
  • timeStamp

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

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

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

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

url 那里一定一定要注意,對(duì)于 SPA 應(yīng)用悯辙,路由前綴那里琳省,絕對(duì)不能只有一個(gè)#,微信的這個(gè)安全機(jī)制很傻屄躲撰。首先你需要去商戶(hù)平臺(tái)那里注冊(cè) JSAPI 支付允許的“支付目錄”(我暈针贬,目錄),然后在調(diào)用 JSAPI 支付的時(shí)候他們會(huì)校驗(yàn)?zāi)愕刂窓凇痹凇安弧痹凇耙炎?cè)的“支付目錄”拢蛋,不在就拒絕下單桦他。我猜他們這個(gè)機(jī)制是做給服務(wù)器端渲染頁(yè)面的應(yīng)用做的:你會(huì)發(fā)現(xiàn)你的 SPA 應(yīng)用拿到的 URL 經(jīng)常跟他們微信拿到的 URL 不匹配,從而一直提示你 URL 未注冊(cè) 然后拒絕下單谆棱。這其實(shí)不算坑快压,文檔在很隱蔽的地方提及需要前端拿這個(gè) sign 去調(diào)用 JSAPI 支付 and 支付前需要調(diào)用 config 一次才是坑死人。

這個(gè)簽名是這樣的垃瞧,如下參數(shù)全小寫(xiě)嗓节,嚴(yán)格按照字典順序排序:

  • jsapi_ticket(我一直不知道這個(gè)東西的存在,因?yàn)槲臋n里面沒(méi)有提及)
  • noncestr(小寫(xiě)皆警,小心)
  • timestamp (小寫(xiě)拦宣,小心)
  • url (就是上面提及的 URL)

然后如此拼接:

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

//不算大括號(hào),只是為了好看加上去的

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

那么這個(gè) URL 在商戶(hù)平臺(tái)注冊(cè)的時(shí)候需要注意什么呢菊值?對(duì)于服務(wù)器端渲染頁(yè)面外驱,你需要填寫(xiě)支付頁(yè)面的地址,刪掉最后的”目錄“:

//訂單支付頁(yè)面
https://shinonometn.com/order/pay/1
//注冊(cè)的 URL
https://shinonometn.com/order/pay/

對(duì)于 SPA (單頁(yè)應(yīng)用)來(lái)說(shuō)腻窒,你只需要填寫(xiě)你的應(yīng)用地址昵宇,路由那里怎么方便怎么做手腳。

//帶上路由的 SPA 的頁(yè)面
https://shinonometn.com/?#/order/pay/1
                        ^我就弄了個(gè)問(wèn)號(hào)
//注冊(cè)的 URL
https://shinonometn.com/

唉儿子,就是因?yàn)?JSAPI 的沙雕設(shè)計(jì)我加班到凌晨 2 點(diǎn)陪前端的人調(diào)試瓦哎。

參考鏈接

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蒋譬,隨后出現(xiàn)的幾起案子割岛,更是在濱河造成了極大的恐慌,老刑警劉巖犯助,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件癣漆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡剂买,警方通過(guò)查閱死者的電腦和手機(jī)惠爽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)雷恃,“玉大人疆股,你說(shuō)我怎么就攤上這事费坊〉够保” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵附井,是天一觀的道長(zhǎng)讨越。 經(jīng)常有香客問(wèn)我,道長(zhǎng)永毅,這世上最難降的妖魔是什么把跨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮沼死,結(jié)果婚禮上着逐,老公的妹妹穿的比我還像新娘。我一直安慰自己意蛀,他們只是感情好耸别,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著县钥,像睡著了一般秀姐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上若贮,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天省有,我揣著相機(jī)與錄音,去河邊找鬼谴麦。 笑死蠢沿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匾效。 我是一名探鬼主播搏予,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了雪侥?” 一聲冷哼從身側(cè)響起碗殷,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎速缨,沒(méi)想到半個(gè)月后锌妻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旬牲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年仿粹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片原茅。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吭历,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出擂橘,到底是詐尸還是另有隱情晌区,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布通贞,位于F島的核電站朗若,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏昌罩。R本人自食惡果不足惜哭懈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茎用。 院中可真熱鬧遣总,春花似錦、人聲如沸轨功。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)夯辖。三九已至琉预,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒿褂,已是汗流浹背圆米。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啄栓,地道東北人娄帖。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像昙楚,于是被迫代替她去往敵國(guó)和親近速。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容