溫州西旸鎮(zhèn)小程序支付及退款流程詳解

閱讀 41949  ·  發(fā)布日期 2020-08-24 17:26  ·  溫州優(yōu)光網絡科技有限公司|建站|APP小程序制作|做網站SEO推廣優(yōu)化
【摘要】 微信小程序的支付和退款流程近期在做微信小程序時,涉及到了小程序的支付和退款流程,所以也大概的將這方面的東西看了一個遍,就在這篇博客里總結一下。首先說明一下,微信小程序支付的主要邏輯集中在后端,前端只需攜帶支付所需的數據請求后端接口然后根據返回結果做相應成功失敗處理即可。我在后端使用的是php,當然在這篇博客里我不打算貼... 【溫州小程序開發(fā),溫州微信公眾號,平陽做網站,平陽網站建設公司,平陽小程序商城制作,昆陽萬全做網站,鰲江水頭小程序,蕭江騰蛟微信公眾號,山門順溪南雁海西南麂鳳臥麻步懷溪網絡網店服務,政采云網店管理服務】...

小程序支付及退款流程詳解

微信小程序的支付和退款流程近期在做微信小程序時,涉及到了小程序的支付和退款流程,所以也大概的將這方面的東西看了一個遍,就在這篇博客里總結一下。
首先說明一下,微信小程序支付的主要邏輯集中在后端,前端只需攜帶支付所需的數據請求后端接口然后根據返回結果做相應成功失敗處理即可。
我在后端使用的是php,當然在這篇博客里我不打算貼一堆代碼來說明支付的具體實現,而主要會側重于整個支付的流程和一些細節(jié)方面的東西。
所以使用其他后端語言的朋友有需要也是可以看一下的。
很多時候開發(fā)的需求和相應問題的解決真的要跳出語言語法層面,去從系統(tǒng)和流程的角度考慮。
好的,也不說什么廢話了。
進入正題。
一. 支付支付主要分為幾個步驟:
前端攜帶支付需要的數據(商品id,購買數量等)發(fā)起支付請求后端在接收到支付請求后,處理支付數據,然后攜帶處理后的數據請求 微信服務器 的 支付統(tǒng)一下單接口后端接收到上一步請求微信服務器的返回數據,再次處理,然后返回前端讓前端可以開始支付。
前端進行支付動作前端支付完成后,微信服務器會向后端發(fā)送支付通知(也就是微信要告訴你客戶已經付過錢了),后端根據這個通知確定支付完成,然后就去做支付完成后的相應動作,比如修改訂單狀態(tài),添加交易日志啊等等。
從這幾個步驟可以看出,后端主要的作用就是將支付需要的數據傳給微信服務器,再根據微信服務器的響應確定支付是否完成。
這個流程還是蠻容易理解的。
形象的說,前端就是個顧客,后端就是店家,微信服務器的統(tǒng)一下單接口就像收銀員。
顧客跟店家說, 我是誰誰誰,現在我要付多少多少錢給你買什么什么。
店家就跟收銀員說,那個誰誰誰要付多少錢,你準備收錢吧。
收銀員收到錢 后,就去告訴店家,我已經收到錢了,你給他東西吧。
下面就詳細的說明一下各個步驟的具體實現。
1. 前端請求支付前端請求支付,就是簡單的攜帶支付需要的數據,例如用戶標識,支付金額,支付訂單 ID 等等跟 **你的業(yè)務邏輯有關** 或者跟 **下一步請求微信服務器支付統(tǒng)一下單接口需要的數據有關** 的相關數據,使用微信小程序的 wx.request( ) 去請求后端的支 付接口。
2. 前端請求支付后端接收到前端發(fā)送的支付請求后,可以進行一下相關驗證,例如判斷一下用戶有沒有問題,支付金額對不對等等。
在驗證沒什么問題,可以向微信服務器申請支付之后,后端需要使用 微信規(guī)定的數據格式 去請求微信的支付統(tǒng)一下單接口。
微信規(guī)定的請求數據:這需要較多代碼實現。
因為需要的數據個數較多,而且還需要加密并以 XML 格式發(fā)送。
首先,有以下數據是使用小程序支付必須提供給微信服務器的參數。
小程序 appid。
寫小程序的大概沒有不知道這個的。
。
。
用戶標識 openid。
也就是用戶的小程序標識,在我上篇博客中說明了如何獲取。
商戶號 mch_id 。
申請開通微信支付商戶認證成功后微信發(fā)給你的郵件里有商戶訂單號 out_trade_no 。
商戶為這次支付生成的訂單號總金額 total_fee 。
訂單總金額,很重要的一點是單位是分,要特別注意。
微信服務器回調通知接口地址 notify_url。
微信確認錢已經到賬后,會往這個地址多次發(fā)送消息,告訴你顧客已經付完錢了,你需要返回消息給微信表示你已經收到了通知。
。
這個地址不能有端口號,同時要能直接接受POST方法請求。
交易類型 trade_type 。
微信小程序支付此值統(tǒng)一為 JSAPI商品信息 Body。
類似"騰訊-游戲"這種格式終端IP地址 spbill_create_ip 。
終端地址IP,也就是請求支付的 IP 地址。
隨機字符串 nonce_str 。
需要后端隨機生成的字符串用于保證數據安全。
微信要求不長于32位。
簽名 sign 。
使用上面的所有參數進行相應處理加密生成簽名。
(具體處理方式可見下文代碼,可直接復用。
)在處理好以上所有數據后,將這些數據以 XML 格式整理并以 POST 方法發(fā)送到 微信支付統(tǒng)一下單接口 https://api.mch.weixin.qq.com/pay/unifiedorder 。
3.后端接受微信服務器返回數據微信服務器在接收到支付數據之后,如果數據沒有問題,其會返回用于支付的相應數據,其中非常重要的是 名稱為 prepay_id 的數據字段,需要將此數據返回前端,前端才能繼續(xù)支付。
因此,在后端接收到微信服務器的返回數據后,需要進行相應的處理,最終返回到前端如下數據:
appid 不需多說timeStamp 當前時間戳nonceStr 隨機字符串package 就是上面提到的 prepay_id,不過切記格式如 “prepay_id= prepay_id_item“。
否則會導致錯誤。
signType 加密方式,一般應該是 MD5paySign 對以上數據進行相應處理并加密。
到這里,后端的支付接口已經完成了接收前端支付請求,并返回了前端支付所需數據的功能。
4. 前端發(fā)起支付前端在接收到返回數據后,使用 wx.requestPayment() 來請求發(fā)起支付。
此 API 需要的對象參數各項值就是我們上一步返回的各個數據。
5.后端接受微信服務器回調前端完成支付后,微信服務器確認支付已經完成。
就會向第一步中設置的回調地址發(fā)送通知。
后端的接收回調接口在接收到通知后,就可以判斷支付是否完成,從而決定后續(xù)動作。
需要注意的是,在接收到微信服務器的回調通知后,根據通知的result_code字段判斷支付是否成功。
在接受到成功的通知后,后端需要返回success數據向微信服務器告知已得到回調通知。
否則微信服務器會不停的向后端發(fā)送消息。
另外微信的通知是以XML格式發(fā)送的,在接受處理時需要注意。
微信的大概支付流程就是這樣。
以下是PHP語法的微信支付類,可以比照上面的步驟介紹,加深理解。
在需要支付時,直接傳入參數實例化此類再調用類的 pay 方法即可。
//微信支付類 class WeiXinPay{
//=======【基本信息設置】===================================== //微信公眾號身份的唯一標識 protected $APPID = appid;
//填寫您的appid。
微信公眾平臺里的 protected $APPSECRET = secret;
//受理商ID,身份標識 protected $MCHID = '
11111111'
;
//商戶id //商戶支付密鑰Key protected $KEY = '
192006250b4c09247ec02edce69f6a2d'
;
//回調通知接口 protected $APPURL = '
https://smart.afei.com/receivesuc'
;
//交易類型 protected $TRADETYPE = '
JSAPI'
;
//商品類型信息 protected $BODY = '
wx/book'
;
//微信支付類的構造函數 function __construct($openid,$outTradeNo,$totalFee){
$this->openid = $openid;
//用戶唯一標識 $this->outTradeNo = $outTradeNo;
//商品編號 $this->totalFee = $totalFee;
//總價 }
//微信支付類向外暴露的支付接口 public function pay(){
$result = $this->weixinapp();
return $result;
}
//對微信統(tǒng)一下單接口返回的支付相關數據進行處理 private function weixinapp(){
$unifiedorder=$this->unifiedorder();
$parameters=array( '
appId'
=>$this->APPID,//小程序ID '
timeStamp'
=>'
'
.time().'
'
,//時間戳 '
nonceStr'
=>$this->createNoncestr(),//隨機串 '
package'
=>'
prepay_id='
.$unifiedorder['
prepay_id'
],//數據包 '
signType'
=>'
MD5'
//簽名方式 );
$parameters['
paySign'
]=$this->getSign($parameters);
return $parameters;
}
/* *請求微信統(tǒng)一下單接口 */ private function unifiedorder(){
$parameters = array( '
appid'
=> $this->APPID,//小程序id '
mch_id'
=> $this->MCHID,//商戶id '
spbill_create_ip'
=>$_SERVER['
REMOTE_ADDR'
],//終端ip '
notify_url'
=>$this->APPURL, //通知地址 '
nonce_str'
=> $this->createNoncestr(),//隨機字符串 '
out_trade_no'
=>$this->outTradeNo,//商戶訂單編號 '
total_fee'
=>floatval($this->totalFee), //總金額 '
open_id'
=>$this->openid,//用戶openid '
trade_type'
=>$this->TRADETYPE,//交易類型 '
body'
=>$this->BODY, //商品信息 );
$parameters['
sign'
] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$xml_result = $this->postXmlCurl($xmlData,'
https://api.mch.weixin.qq.com/pay/unifiedorder'
,60);
$result = $this->xmlToArray($xml_result);
return $result;
}
//數組轉字符串方法 protected function arrayToXml($arr){
$xml = "";
foreach ($arr as $key=>$val) {
if (is_numeric($val)){
$xml.="".$val."".$key.">";
}
else{
$xml.="".$key.">";
}
}
$xml.="
";
return $xml;
}
protected function xmlToArray($xml){
$array_data = json_decode(json_encode(simplexml_load_string($xml, '
SimpleXMLElement'
, LIBXML_NOCDATA)), true);
return $array_data;
}
//發(fā)送xml請求方法 private static function postXmlCurl($xml, $url, $second = 30) {
$ch = curl_init();
//設置超時 curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//嚴格校驗 //設置header curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求結果為字符串且輸出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//運行curl $data = curl_exec($ch);
//返回結果 if ($data) {
curl_close($ch);
return $data;
}
else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出錯,錯誤碼:$error");
}
}
/* * 對要發(fā)送到微信統(tǒng)一下單接口的數據進行簽名 */ protected function getSign($Obj){
foreach ($Obj as $k => $v){
$Parameters[$k] = $v;
}
//簽名步驟一:
按字典序排序參數 ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//簽名步驟二:
在string后加入KEY $String = $String."&key=".$this->KEY;
//簽名步驟三:
MD5加密 $String = md5($String);
//簽名步驟四:
所有字符轉為大寫 $result_ = strtoupper($String);
return $result_;
}
/* *排序并格式化參數方法,簽名時需要使用 */ protected function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if($urlencode) {
$v = urlencode($v);
}
//$buff .= strtolower($k) . "=" . $v . "&";
$buff .= $k . "=" . $v . "&";
}
$reqPar;
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff)-1);
}
return $reqPar;
}
/* * 生成隨機字符串方法 */ protected function createNoncestr($length = 32 ){
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0;
$i $i++ ) {
$str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
}
以上就是微信支付的相關流程。
在理清思路后,流程還是比較清晰和簡單的。
重點在于需要注意一些細節(jié)問題,例如數據格式,加密方法等。
下面說一下微信小程序退款的具體實現二.退款小程序退款的流程和付款相似,但有一些細節(jié)上的不同。
首先退款的步驟通常如下:用戶前端點擊退款按鈕后,后端接收到用戶的退款請求通過商城后臺呈現給商戶,商戶確定允許退款后,后端再發(fā)起向微信退款接口的請求來請求退款。
后端向微信退款接口發(fā)送請求后,得到響應信息,確定退款是否完成,根據退款是否完成再去進行改變訂單狀態(tài)等業(yè)務邏輯。
退款的步驟相對微信支付來說比較簡單。
值得注意的有以下兩點:
1.向微信退款接口請求退款后,根據得到的響應是可以直接確定退款是否完成的。
不再需要設置專門的回調接口等待微信通知。
當然如果需要也是可以在微信商戶平臺設置回調接口接受從而接受微信回調的,但并不是必須的。
2.退款請求需要在請求服務器安裝微信提供的安全證書,也就是說,發(fā)起退款請求相比較支付請求在請求時請求方法不能復用,因為微信退款需要攜帶證書的請求,此證書可在申請微信商戶號成功后從微信商戶平臺自行下載,Linux下的PHP開發(fā)環(huán)境的證書只需要放在網站根目錄的cert文件夾中即可。
其他開發(fā)環(huán)境可能需要導入操作。
下面講解一下退款的具體步驟一. 用戶發(fā)起退款請求用戶在前端發(fā)起退款請求,后端接收到退款請求,將相應訂單標記為申請退款,展示在后臺.商戶查看后,如果同意退款再進行相應操作. 此后才進入真正的退款流程.二. 商戶發(fā)起退款請求 商戶同意退款后,后端即向微信提供的退款 API 發(fā)起請求. 同請求微信支付API一樣.退款請求也需要將需要的參數進行簽名后以XML發(fā)送到微信的退款API [https://api.mch.weixin.qq.com/pay/refund](https://api.mch.weixin.qq.com/pay/refund)退款請求需要的參數如下(多個參數在支付API請求時也有使用):小程序 appid。
商戶號 mch_id 。
申請開通微信支付商戶認證成功后微信發(fā)給你的郵件里有商戶訂單號 out_trade_no 。
退款訂單在支付時生成的訂單號退款訂單號 out_refund_no 。
由后端生成的退款單號,需要保證唯一,因為多個同樣的退款單號只會退款一次。
總金額 total_fee 。
訂單總金額,單位為分。
退款金額 refund_fee 需要退款的金額,單位同樣為分操作員 op_user_id .與商戶號相同即可隨機字符串 nonce_str 。
同支付請求簽名 sign 。
使用上面的所有參數進行相應處理加密生成簽名。
(具體處理方式與支付相同,可直接復用。
)三. 退款完成在發(fā)起退款請求后,就可以直接根據請求的響應XML中的 result_code字段來判斷退款是否成功, 從而對訂單狀態(tài)進行處理和后續(xù)操作。
不需要像支付那樣等待另一個接口的通知來確定請求狀態(tài)。
當然如上文所說, 如果需要微信服務器發(fā)送通知到后端的話,可以到微信商戶平臺進行設置。
退款因為流程與支付大同小異,因此退款的PHP類我選擇了直接繼承支付類,代碼如下,注意區(qū)分退款請求方法postXmlSSLCurl和支付請求方法postXmlCurl的區(qū)別,這也就是上文提到的退款需要的雙向證書的使用。
class WinXinRefund extends WeiXinPay{
protected $SSLCERT_PATH = '
cert/apiclient_cert.pem'
;
//證書路徑 protected $SSLKEY_PATH = '
cert/apiclient_key.pem'
;
//證書路徑 protected $opUserId = '
1234567899'
;
//商戶號 function __construct($openid,$outTradeNo,$totalFee,$outRefundNo,$refundFee){
//初始化退款類需要的變量 $this->openid = $openid;
$this->outTradeNo = $outTradeNo;
$this->totalFee = $totalFee;
$this->outRefundNo = $outRefundNo;
$this->refundFee = $refundFee;
}
public function refund(){
//對外暴露的退款接口 $result = $this->wxrefundapi();
return $result;
}
private function wxrefundapi(){
//通過微信api進行退款流程 $parma = array( '
appid'
=> $this->APPID, '
mch_id'
=> $this->MCHID, '
nonce_str'
=> $this->createNoncestr(), '
out_refund_no'
=> $this->outRefundNo, '
out_trade_no'
=> $this->outTradeNo, '
total_fee'
=> $this->totalFee, '
refund_fee'
=> $this->refundFee, '
op_user_id'
=> $this->opUserId, );
$parma['
sign'
] = $this->getSign($parma);
$xmldata = $this->arrayToXml($parma);
$xmlresult = $this->postXmlSSLCurl($xmldata,'
https://api.mch.weixin.qq.com/secapi/pay/refund'
);
$result = $this->xmlToArray($xmlresult);
return $result;
}
//需要使用證書的請求 function postXmlSSLCurl($xml,$url,$second=30) {
$ch = curl_init();
//超時時間 curl_setopt($ch,CURLOPT_TIMEOUT,$second);
//這里設置代理,如果有的話 //curl_setopt($ch,CURLOPT_PROXY, '
8.8.8.8'
);
//curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
//設置header curl_setopt($ch,CURLOPT_HEADER,FALSE);
//要求結果為字符串且輸出到屏幕上 curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
//設置證書 //使用證書:
cert 與 key 分別屬于兩個.pem文件 //默認格式為PEM,可以注釋 curl_setopt($ch,CURLOPT_SSLCERTTYPE,'
PEM'
);
curl_setopt($ch,CURLOPT_SSLCERT, $this->SSLCERT_PATH);
//默認格式為PEM,可以注釋 curl_setopt($ch,CURLOPT_SSLKEYTYPE,'
PEM'
);
curl_setopt($ch,CURLOPT_SSLKEY, $this->SSLKEY_PATH);
//post提交方式 curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
$data = curl_exec($ch);
//返回結果 if($data){
curl_close($ch);
return $data;
}
else {
$error = curl_errno($ch);
echo "curl出錯,錯誤碼:$error"."
";
curl_close($ch);
return false;
}
}
}
## 三. 總結 以上就是關于微信支付和退款的流程及相關知識的介紹。
文中的 PHP類 均封裝直接可用。
因為微信支付和退款涉及的東西較為繁雜,很多人直接看官方文檔可能會一頭霧水,所以看過此文了解流程和要點后,再去看微信官方文檔。
一方面可以更清晰的了解小程序的支付和退款流程。
另一方面,本文因為篇幅有限及作者能力有限,肯定有無暇顧及或有所紕漏之處。
為求穩(wěn)妥,還是需要多看看官方開發(fā)文檔。
畢竟事涉支付,出個BUG可不是小事。
最后扯點閑話吧。
這篇博客本來應該在三個月前就發(fā)表的,也算當時我從一無所知到獨立完成微信小程序商城前后端的總結系列的第一篇。
但是公司突然出現人員和項目的變動,導致管理和項目上都混亂不堪,再加上個人的惰性,導致此篇博客一直拖到三個月后的今天才斷斷續(xù)續(xù)寫完。
這三個月我的心態(tài)因為各種事起起伏伏,也頗有一番風味。
借用李志的一句歌詞結束這篇博客吧。

下一篇是什么時候也說不定了,我苦笑。
>我再也不會把自己,愚蠢的交給過去。
我的生活和我的想法,從此相隔萬里。
推薦教程:
《微信小程序》以上就是小程序支付及退款流程詳解的詳細內容,更多請關注php中文網其它相關文章!
微信
分享相關標簽:
微信小程序本文轉載于:
博客園,如有侵犯,請聯(lián)系[email protected]刪除
上一篇:
小程序中解決代碼同步執(zhí)行的問題
下一篇:
微信小程序 暗黑模式相關文章相關視頻小程序new Date()方法失效怎么辦八分鐘帶你入門微信小程序開發(fā)小程序頁面間傳遞數據的方式小程序畫布canvas隱藏的問題解決小程序支付及退款流程詳解認識小程序開發(fā)工具認識小程序的目錄結構小程序的rpx長度單位詳解 [溫州做小程序]