微信支付回調通知
一、提要
接上一篇文章,JSAPI支付完成之後,會把相關支付結果及用戶信息通過數據流的形式發送給商戶,商戶需要接收處理,並按文檔規範返回應答。
二、準備資料
- JSAPI支付中,調用微信統一下單接口中配置了notify_url參數
- 參考微信文檔【回調通知注意事項】
在微信回調通知注意事項中,微信有以下提示信息:
- notify_url需要填寫商戶自己系統的真實地址,不能填寫接口文檔或demo上的示例地址。
- notify_url必須是以https://或http://開頭的完整全路徑地址,並且確保url中的域名和IP是外網可以訪問的,不能填寫localhost、127.0.0.1、192.168.x.x等本地或內網IP。
- notify_url不能攜帶參數。
更多注意事項,請參考微信文檔:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_8&index=6
- 參考微信文檔【支付結果通知】
注意事項:
- 同樣的通知可能會多次發送給商戶系統。商戶系統必須能夠正確處理重複的通知。
- 後臺通知交互時,如果微信收到商戶的應答不符合規範或超時,微信會判定本次通知失敗,重新發送通知,直到成功爲止(在通知一直不成功的情況下,微信總共會發起多次通知,通知頻率爲15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計 24h4m),但微信不保證通知最終一定能成功。
- 在訂單狀態不明或者沒有收到微信支付結果通知的情況下,建議商戶主動調用微信支付【查詢訂單API】確認訂單狀態。
特別提醒:
- 商戶系統對於支付結果通知的內容一定要做簽名驗證,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止數據泄漏導致出現“假通知”,造成資金損失。
- 當收到通知進行處理時,首先檢查對應業務數據的狀態,判斷該通知是否已經處理過,如果沒有處理過再進行處理,如果處理過直接返回結果成功。在對業務數據進行狀態檢查和處理之前,要採用數據鎖進行併發控制,以避免函數重入造成的數據混亂。
- 技術人員可登進微信商戶後臺掃描加入接口報警羣,獲取接口告警信息。
更多參考信息,請參照文檔:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
三、代碼開發
請注意,微信的支付結果通知,由於需要提交數據流,所以請求方式爲:Post。
//請注意,一定要在方法體頭部加入Post請求標識
[HttpPost]
public string SyUnifiedorderUrl()
接收Xml文件流
string strRecieveBody;
using (System.IO.StreamReader streamReader = new System.IO.StreamReader(Request.Body))
{
strRecieveBody = streamReader.ReadToEnd();
//方面我們更好的處理該Xml文件,建議使用日誌打印該文件流結果
}
建議將xml轉換爲對象或者Dictionary<string, string>對象以方便我們更好的處理,由於微信通知返回的字段過於繁雜,並且很多字段其實都無關業務數據處理,所以,在此在建議各位將返回結果轉換爲Dictionary<string, string>。
public IDictionary<string, string> FromXml(string xml)
{
IDictionary<string, string> xmlDic = new Dictionary<string, string>();
if (string.IsNullOrEmpty(xml))
{
return xmlDic;
}
XmlDocument xmlDoc = new XmlDocument();
// 2018/07/06 關於XML解析存在的安全問題指引.Net回調修復
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(xml);
XmlNode xmlNode = xmlDoc.FirstChild;//獲取到根節點<xml>
XmlNodeList nodes = xmlNode.ChildNodes;
foreach (XmlNode xn in nodes)
{
XmlElement xe = (XmlElement)xn;
xmlDic[xe.Name] = xe.InnerText;//獲取xml的鍵值對到WxPayData內部的數據中
}
return xmlDic;
}
針對該返回結果,我們需要着重處理的字段如下:
return_code:返回狀態碼,SUCCESS/FAIL;交易是否成功需要查看result_code來判斷。
sign:簽名,我們需要對數字簽名進行驗證,防止數據泄漏導致出現“假通知”,我們可以使用
out_trade_no:商戶訂單號,我們可根據該字段查詢我們數據庫中的訂單,然後再進行業務處理。
total_fee:訂單總金額,我們可根據該字段校驗,我們發起支付的金額與用戶實際支付金額是否一致
等這一切都校驗完成,一整套jsapi支付纔算結束。