微信App支付技術架構全解析

本文來自做者原創投稿;
博客:http://www.jianshu.com/users/21716b19302d/latest_articlesphp

.html

簡單介紹了微信移動支付的申請、接入、使用、確認支付結果等相關流程git

1 申請

申請步驟直接參考官方文檔-http://kf.qq.com/faq/120911VrYVrA150906F3qqY3.htmlgithub

主要2個大塊:json

  1. 申請開通開放平臺
  2. 申請支付開通商戶平臺
    所有申請經過後,獲取支付必須的參數以下:

1.1 AppID和AppSecret

開放平臺建立的應用惟一標識。 登陸微信開放平臺,進入應用詳情可查看AppID和AppSecret。api

微信App支付技術架構全解析

微信App支付技術架構全解析

1.2 mch_id

微信支付申請完成以後,微信商戶平臺會給你的郵箱發通知郵件,裏面包含開通支付的商戶信息數組

微信App支付技術架構全解析

1.3 API祕鑰

即商戶支付祕鑰,主要負責處理通訊相關參數加密。登錄微信商戶平臺(帳號密碼在微信商戶平臺發來的郵件裏) 點擊左側的「帳戶設置 - API 安全」(第一次登錄會讓你安裝操做證書,請先安裝操做證書)。點擊設置密鑰,設置本身的密鑰。安全

微信App支付技術架構全解析

1.4 商戶證書

用於退款等一些須要證書驗證的接口使用。在微信商戶平臺點擊「帳戶中心 - API 安全」,點擊「下載證書」微信

微信App支付技術架構全解析

證書下載後,打開壓縮包會看到「apiclientcert.pem」和「apiclientkey.pem」和rootca.pem證書。網絡

2 接入流程


參考接入文檔-https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1

主要幾個步驟:

  1. 統一下單(放在服務端,須要加密參數)
  2. 生成支付參數(放在服務端,須要生成簽名)
  3. 調用客戶端SDK發起支付
  4. 服務端異步接收支付結果

    2.1 統一下單

$appid = "";  //你的appid
$mch_id = "";  //商戶id
$wx_api_key = "";    //商戶api祕鑰
$out_trade_no = "";  //本身業務系統生成的交易no,能夠惟一標識
$client_ip = "";  //客戶端ip
$notify_url = "";    //接收支付結果通知url

$UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";  //統一下單地址

$data = array();
$data['appid'] = $appid; 
$data['mch_id'] =$mch_id;
$data['nonce_str'] = randomStr(20);  //隨機20位字符串
$data['body'] = "微信移動支付測試";
$data['detail'] = "微信移動支付測試";
$data['out_trade_no'] = $out_trade_no;    
$data['total_fee'] = 1;  //注意 單位是分
$data['spbill_create_ip'] = $client_ip;
$data['notify_url'] = $notify_url;
$data['trade_type'] = "APP";  //交易類型
$data['sign'] =sign($data, $wx_api_key);    //簽名

//轉爲xml格式
$xml_str = arrayToXmlStr($data); 

//發送請求 使用封裝好的curl_post
$result = curl_post($UNIFIED_ORDER_URL, $xml_str);

//解析獲得的值
$get_data = simplexml_load_string($raw_data, 'SimpleXMLElement', LIBXML_NOCDATA);
$get_para = array();
$get_sign = "";
foreach ($get_data->children() as $child) 
{    
    if($child->getName() == 'sign') {        
        $get_sign = strval($child);    
    } else {        
        $get_para[strval($child->getName())] = strval($child);    
    }
}

if($get_para['return_code'] !== "SUCCESS") {
    //return code fail
}

//驗證簽名
if(!verifySign($get_sign, $get_para, $wx_api_key)) {
    //驗證簽名非法
}

//能夠自行處理解析得到的參數
//todo...

一些函數:

/**
 * array轉成xml str
 * @param $arr
 */
public static function arrayToXmlStr($arr) {    
    $xml_data = new \SimpleXMLElement("<xml></xml>");    
    Func::arrayToXml($arr, $xml_data);    
    return $xml_data->asXML();
}

/**
 * 生成指定長度的隨機字符串(包含大寫英文字母, 小寫英文字母, 數字)
 * @param $length int 須要生成的字符串的長度
 * @return string 包含 大小寫英文字母 和 數字 的隨機字符串
 */
public static function randomStr($length){    
    //生成一個包含 大寫英文字母, 小寫英文字母, 數字 的數組    
    $arr = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));    
    $str = '';    
    $arr_len = count($arr);    
    for ($i = 0; $i < $length; $i++)    {        
        $rand = mt_rand(0, $arr_len-1);        
        $str.=$arr[$rand];    
    }    
    return $str;
}

/**
 * 微信簽名
 * @param $para mixed 帶簽名參數數組
 * @param $wx_key string wxkey
 */
public static function sign($para, $wx_key) {    
    $unsign_str = Func::createLinkString(Func::argSort($para)) . "&key=" . $wx_key;    
    $sign = strtoupper(md5($unsign_str));    
    return $sign;
}

/**
 * 微信簽名驗證
 * @param $sign
 * @param $para
 * @param $wx_key
 * @return false-驗證失敗 true-驗證成功
 */
public static function verifySign($sign, $para, $wx_key) {    
    $unsign_str = Func::createLinkString(Func::argSort($para)) . "&key=" . $wx_key;    
    $sign_str = strtoupper(md5($unsign_str));    
    if($sign === $sign_str) {        
    return true;    
    }    
    return false;
}

2.2 生成支付參數

客戶端須要的支付參數是帶簽名的,因此最好支付參數也在服務端生成後,jsondecode後傳入客戶端便可直接調用

//生成支付參數
$data = array();
$data['appid'] = $appid; 
$data['mch_id'] =$mch_id;
$data['prepayid'] = $prepayid;    //剛纔統一下單生成的prepayid
$data['package'] = "Sign=WXPay";
$data['noncestr'] = randomStr(20);
$data['timestamp'] = time();
$data['sign'] =sign($data, $wx_api_key);

$pay_param = json_encode($data);

3. 調用支付

3.1 Android

注:微信支付在開放平臺中填入應用對應的包名和簽名,而且測試時要簽名打包,否則支付失敗

能夠直接參考調用我二次封裝過的Android SDK。 Github地址:https://github.com/tsy12321/PayAndroid

3.2 iOS

二次封裝過的iOS SDK。 Github地址:https://github.com/tsy12321/PayiOS

4 異步結果通知

注:尤爲要注意通知結果驗證成功後要能正確處理重複通知,放置屢次發貨形成資金損失

$raw_data = $GLOBALS["HTTP_RAW_POST_DATA"];

$get_data = simplexml_load_string($raw_data, 'SimpleXMLElement', LIBXML_NOCDATA);
$get_para = array();
$get_sign = "";
foreach ($get_data->children() as $child) 
{    
    if($child->getName() == 'sign') {        
        $get_sign = strval($child);    
    } else {        
        $get_para[strval($child->getName())] = strval($child);    
    }
}

if($get_para['return_code'] !== "SUCCESS") {
    //return code fail
    die("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
}

//驗證簽名
if(!verifySign($get_sign, $get_para, $wx_api_key)) {
    //驗證簽名非法
    //todo
    die("<xml><return_code><![CDATA[FAIL]]></return_code></xml>");
}

//在這其實通知已經接受成功 能夠返回成功告訴微信不用再次通知了
echo("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");

//業務狀態碼判斷
if ($get_para['result_code'] !== 'SUCCESS') {       
    //狀態碼錯誤
    //支付錯誤 更改訂單狀態 記錄log等 
    //...
}

//支付成功 更改訂單狀態 記錄log等 
//todo

5 其餘

客戶端收到同步支付結果後建議一段時間內輪詢檢查服務端,獲取服務端的結果,支付最終狀態以服務端爲準

版權申明:內容來源網絡,版權歸原創者全部。除非沒法確認,咱們都會標明做者及出處,若有侵權煩請告知,咱們會當即刪除並表示歉意。謝謝。

-END-
微信App支付技術架構全解析
架構文摘
ID:ArchDigest
互聯網應用架構丨架構技術丨大型網站丨大數據丨機器學習
微信App支付技術架構全解析更多精彩文章,請點擊下方:閱讀原文

相關文章
相關標籤/搜索