摘要:本文是淺析微信支付系列文章的第六篇,主要講解支付成功后,微信回調(diào)商戶支付結(jié)果通知的處理。微信支付支付回調(diào)接口該鏈接是通過統(tǒng)一下單中提交的參數(shù)設(shè)置,如果鏈接無法訪問,商戶將無法接收到微信通知。
本文是【淺析微信支付】系列文章的第六篇,主要講解支付成功后,微信回調(diào)商戶支付結(jié)果通知的處理。
淺析微信支付系列已經(jīng)更新五篇了喲~,沒有看過的朋友們可以看一下哦。
淺析微信支付:統(tǒng)一下單接口
淺析微信支付:微信公眾號網(wǎng)頁授權(quán)
淺析微信支付:開發(fā)前的準備
前面一章已經(jīng)講了如何調(diào)用統(tǒng)一下單接口和調(diào)起微信支付窗口,在調(diào)用下單接口時,我們會傳入 異步接收微信支付結(jié)果通知的回調(diào)地址,顧名思義這個地址作用就是用來接收支付結(jié)果通知,當(dāng)用戶在前端支付成功后,微信服務(wù)器會自動調(diào)用此地址,然后商戶再進行處理。
1、支付結(jié)果通知以下為接口官方解釋:
支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應(yīng)答。 對后臺通知交互時,如果微信收到商戶的應(yīng)答不是成功或超時,微信認為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒) 注意:同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 推薦的做法是,當(dāng)收到通知進行處理時,首先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進行處理,如果處理過直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。 特別提醒:商戶系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。 技術(shù)人員可登進微信商戶后臺掃描加入接口報警群。
支付結(jié)果通知接口文檔地址:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
需要注意的事項有以下幾點:
1. 該鏈接是通過【統(tǒng)一下單API】中提交的參數(shù)notify_url設(shè)置,如果鏈接無法訪問,商戶將無法接收到微信通知。 2. 通知url必須為直接可訪問的url,不能攜帶參數(shù),也就是必須使用外網(wǎng)接口地址,不能使用本地調(diào)試地址 3. 商戶需要接收處理,并返回應(yīng)答。如果微信收到商戶的應(yīng)答不是成功或超時,微信認為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 4. 通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒 5. 同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 6. 特別提醒:商戶系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
PS:推薦的做法是,當(dāng)收到通知進行處理時,首先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進行處理,如果處理過直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。
關(guān)于具體的簽名和接收通知代碼如下:
package imall.controller.wx; package ... /** * 微信支付Controller * * @author yclimb * @date 2018/6/15 */ @Api @RestController @RequestMapping("/weixin/pay") public class WXPayController extends BaseController { // 需要注入的一些service /** * 返回成功xml */ private String resSuccessXml = ""; /** * 返回失敗xml */ private String resFailXml = " "; /** * 該鏈接是通過【統(tǒng)一下單API】中提交的參數(shù)notify_url設(shè)置,如果鏈接無法訪問,商戶將無法接收到微信通知。 * 通知url必須為直接可訪問的url,不能攜帶參數(shù)。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action” * * 支付完成后,微信會把相關(guān)支付結(jié)果和用戶信息發(fā)送給商戶,商戶需要接收處理,并返回應(yīng)答。 * 對后臺通知交互時,如果微信收到商戶的應(yīng)答不是成功或超時,微信認為通知失敗,微信會通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。 * (通知頻率為15/15/30/180/1800/1800/1800/1800/3600,單位:秒) * 注意:同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 * 推薦的做法是,當(dāng)收到通知進行處理時,首先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),判斷該通知是否已經(jīng)處理過,如果沒有處理過再進行處理,如果處理過直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。 * 特別提醒:商戶系統(tǒng)對于支付結(jié)果通知的內(nèi)容一定要做簽名驗證,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。 * * @author yclimb * @date 2018/6/15 */ @ApiOperation(value = "微信支付|支付回調(diào)接口", httpMethod = "POST", notes = "該鏈接是通過【統(tǒng)一下單API】中提交的參數(shù)notify_url設(shè)置,如果鏈接無法訪問,商戶將無法接收到微信通知。") @RequestMapping("/wxnotify") public void wxnotify(HttpServletRequest request, HttpServletResponse response) { String resXml = ""; InputStream inStream; try { inStream = request.getInputStream(); ByteArrayOutputStream outSteam = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outSteam.write(buffer, 0, len); } WXPayUtil.getLogger().info("wxnotify:微信支付----start----"); // 獲取微信調(diào)用我們notify_url的返回信息 String result = new String(outSteam.toByteArray(), "utf-8"); WXPayUtil.getLogger().info("wxnotify:微信支付----result----=" + result); // 關(guān)閉流 outSteam.close(); inStream.close(); // xml轉(zhuǎn)換為map Map
resultMap = WXPayUtil.xmlToMap(result); boolean isSuccess = false; if (WXPayConstants.SUCCESS.equalsIgnoreCase(resultMap.get(WXPayConstants.RESULT_CODE))) { WXPayUtil.getLogger().info("wxnotify:微信支付----返回成功"); if (WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY)) { // 訂單處理 操作 orderconroller 的回寫操作? WXPayUtil.getLogger().info("wxnotify:微信支付----驗證簽名成功"); // 通知微信.異步確認成功.必寫.不然會一直通知后臺.八次之后就認為交易失敗了. resXml = resSuccessXml; isSuccess = true; } else { WXPayUtil.getLogger().error("wxnotify:微信支付----判斷簽名錯誤"); } } else { WXPayUtil.getLogger().error("wxnotify:支付失敗,錯誤信息:" + resultMap.get(WXPayConstants.ERR_CODE_DES)); resXml = resFailXml; } // 付款記錄修改 & 記錄付款日志 // 回調(diào)方法,處理業(yè)務(wù) - 修改訂單狀態(tài) WXPayUtil.getLogger().info("wxnotify:微信支付回調(diào):修改的訂單===>" + resultMap.get("out_trade_no")); int updateResult = ...; if (updateResult > 0) { WXPayUtil.getLogger().info("wxnotify:微信支付回調(diào):修改訂單支付狀態(tài)成功"); } else { WXPayUtil.getLogger().error("wxnotify:微信支付回調(diào):修改訂單支付狀態(tài)失敗"); } } catch (Exception e) { WXPayUtil.getLogger().error("wxnotify:支付回調(diào)發(fā)布異常:", e); } finally { try { // 處理業(yè)務(wù)完畢 BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); } catch (IOException e) { WXPayUtil.getLogger().error("wxnotify:支付回調(diào)發(fā)布異常:out:", e); } } } }
驗證是否本商戶返回的正確通知:
// xml轉(zhuǎn)換為map MapresultMap = WXPayUtil.xmlToMap(result); // 判斷簽名是否正確,必須包含sign字段,否則返回false。使用MD5簽名。 WXPayUtil.isSignatureValid(resultMap, WXPayConstants.API_KEY);
從以上代碼可以得知,微信是以流的方式來調(diào)用支付結(jié)果通知,流中數(shù)據(jù)格式為xml,所以需要先對流進行解析,然后再將xml轉(zhuǎn)換為map,上面方法已經(jīng)實現(xiàn)這個過程,有現(xiàn)成的代碼可供參考,無需再重新編寫代碼。
需要注意的是,不論成功或者失敗,必須向微信返回對應(yīng)的返回值,如上方代碼中的resSuccessXml、resFailXml,否則會引起重復(fù)調(diào)用的問題,在代碼中我們應(yīng)該規(guī)避風(fēng)險。
2、對于支付單的處理在收到支付結(jié)果后,我們會對系統(tǒng)中的支付單進行狀態(tài)修改等操作,此時需要注意,如果微信返回失敗,接口直接返回失敗即可;
如果微信通知付款成功,返回時有一個 out_trade_no 參數(shù),此參數(shù)為調(diào)用 統(tǒng)一下單接口 時傳入微信的支付單號,可根據(jù)此參數(shù)取得對應(yīng)的支付單,然后進行修改操作,若操作時出現(xiàn)異常,一定要向微信返回錯誤的xml代碼,用微信的重試機制來二次回調(diào),否則就需要記錄通知信息,在本系統(tǒng)自動重試來解決。
在處理微信驗證數(shù)據(jù)時,還需要注意微信最終返回的結(jié)果中是否使用了代金券,如果使用了代金券,還需要另行處理,此處先不詳細描述,后面章節(jié)會詳細解釋代金券的操作。
結(jié)語以上為 微信支付結(jié)果通知接口 的接收方式,它是一個微信服務(wù)自身控制的異步調(diào)用方法,在自身商戶系統(tǒng)中需要處理很多異常,如網(wǎng)絡(luò)抖動和服務(wù)異常等問題,所以盡量在商戶系統(tǒng)中保存微信結(jié)果通知數(shù)據(jù)和增加失敗重試機制,保證數(shù)據(jù)的正確性。
預(yù)告:下一篇文章 查詢訂單和關(guān)閉訂單,敬請期待?。?!
?如果想要提前一覽源碼的小伙伴,可以先看看我的 github,地址如下: https://github.com/YClimb/wxpay-sdk/blob/master/README.md
加作者私人微信,作者微信號如下 yclimb,標明 微信支付 可拉入微信支付討論群與小伙伴一起探討哦,一定要標明 微信支付 哦~
到此本文就結(jié)束了,關(guān)注公眾號查看更多推送!??!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/72063.html
摘要:本文是淺析微信支付系列文章的第十篇,主要講解如何使用沙箱環(huán)境來測試微信支付。圖為微信支付仿真測試系統(tǒng)后簡稱仿真系統(tǒng)的簡化原理圖。沙箱說明微信支付沙箱環(huán)境,是提供給微信支付商戶的開發(fā)者,用于模擬支付及回調(diào)通知。 本文是【淺析微信支付】系列文章的第十篇,主要講解如何使用沙箱環(huán)境來測試微信支付。 淺析微信支付系列已經(jīng)更新十篇了喲~,沒有看過的朋友們可以看一下。 淺析微信支付:下載對賬單和資...
摘要:淺析微信支付前篇大綱本文是淺析微信支付系列文章的第一篇,主要會介紹一下為何寫下這個系列以及對于微信支付的一點小經(jīng)驗,與君共勉。下面講一下我是如何去學(xué)習(xí)微信支付的。 淺析微信支付:前篇大綱 本文是【淺析微信支付】系列文章的第一篇,主要會介紹一下為何寫下這個系列以及對于微信支付的一點小經(jīng)驗,與君共勉。 以下會分幾個步驟講一下我學(xué)習(xí)微信支付的過程,也是一部辛酸史,也是希望朋友們不要再次跌進...
摘要:注意交易時間超過一年的訂單無法提交退款微信支付退款支持單筆交易分多次退款,多次退款需要提交原支付訂單的商戶訂單號和設(shè)置不同的退款單號。 本文是【淺析微信支付】系列文章的第八篇,主要講解商戶如何處理微信申請退款、退款回調(diào)、查詢退款接口,其中有一些坑的地方,會著重強調(diào)。 淺析微信支付系列已經(jīng)更新七篇了喲~,沒有看過的朋友們可以看一下哦。 淺析微信支付:查詢訂單和關(guān)閉訂單 淺析微信支付:支...
摘要:本文是淺析微信支付系列文章的第五篇,主要講解如何調(diào)用統(tǒng)一下單接口生成預(yù)支付單及調(diào)起支付頁面。淺析微信支付系列已經(jīng)更新四篇了喲,沒有看過的朋友們可以看一下哦。 本文是【淺析微信支付】系列文章的第五篇,主要講解如何調(diào)用統(tǒng)一下單接口生成預(yù)支付單及調(diào)起支付頁面。 淺析微信支付系列已經(jīng)更新四篇了喲~,沒有看過的朋友們可以看一下哦。 淺析微信支付:微信公眾號網(wǎng)頁授權(quán) 淺析微信支付:開發(fā)前的準備 ...
摘要:本文是淺析微信支付系列文章的第七篇,主要講解微信商戶平臺的訂單查詢和關(guān)閉接口的使用。查詢訂單以下為微信官方的查詢訂單文檔應(yīng)用場景該接口提供所有微信支付訂單的查詢,商戶可以通過查詢訂單接口主動查詢訂單狀態(tài),完成下一步的業(yè)務(wù)邏輯。 本文是【淺析微信支付】系列文章的第七篇,主要講解微信商戶平臺的訂單查詢和關(guān)閉接口的使用。 淺析微信支付系列已經(jīng)更新六篇了喲~,沒有看過的朋友們可以看一下哦。 ...
閱讀 3568·2021-10-09 09:41
閱讀 2770·2021-10-08 10:18
閱讀 2213·2021-09-10 10:51
閱讀 2707·2021-09-10 10:50
閱讀 803·2021-09-09 09:33
閱讀 3405·2021-09-06 15:14
閱讀 3060·2019-08-30 11:06
閱讀 3268·2019-08-29 14:04