支付寶和微信移動支付的個人總結
今天在看了移動支付的文件,對整個流程都有了自己的理解,在這裡記錄下來自己的總結,把裡面的邏輯都整理一遍
一、支付寶支付
先去看官方的支付文件,連結如下
1、先說前期準備,關鍵就是要生成一對公鑰和私鑰,這個看官方文件,現在官方有個自動生成工具,其實挺方便的。注意的是如果是java開發,生成的私鑰要轉成pkcs8格式。
(1)pkcs8的私鑰自己儲存,填到自己支付寶開發專案 裡面的public static final String RSA_PRIVATE 這個欄位裡
(2)下面的藍色2個選項,其實都是公鑰。前個是自己上傳的公鑰,後一個是對應的支付寶公鑰,這個支付寶公鑰才是我們開發中需要的,這個切記。
(3)點紅色方框,把自己生成的公鑰上傳給支付寶。
(4)點藍色方框,得到支付寶的公鑰,填到public static final String RSA_PUBLIC 這個欄位裡
2、準備完成了,接下來就是看請求引數的文件,這裡告訴我們究竟要如何上傳引數給支付寶後臺,文件連結如下。
其實,支付寶接入的核心就是要組成下面圖片所示的字串,把這個字串當引數傳遞呼叫支付寶Api即可。
我們來分析這個字串。紅色邊框裡面是簽名內容sign和加密名稱sign_type。(sign是根據我們上傳引數生成的,也就是說所有我們上傳的引數都需要一起簽名;sign_type是簽名方法,這裡是固定值RSA)。而紅色邊框之外的是我們自己根據需要拼接的引數資料。接下來就是2個疑問
(1)紅色邊框之外的內容如何生成?
(2)紅色邊框裡面的簽名又是如何生成?
我們一個個來,先說紅色邊框之外的內容,把所有 值以key= “value”進行組合,之後用“&”字元連線起來,支援無序。 根據demo,我們使用一個String orderInfo = getOrderInfo("測試的商品", "該測試商品的詳細描述", "0.01")方法得到這個字串,而這個orderInfo就是紅色邊框之外的內容。
這個方法需要傳遞3個引數,第1個是商品的名字或者訂單編號等,第2個是描述資訊,第3個是支付的總金額。那麼這個getOrderInfo的方法是怎麼實現的,看下面程式碼。
可以看到,上面的這個方法就是根據請求引數說明,拼接字串而已。private String getOrderInfo(String subject, String body, String price) { // 簽約合作者身份ID String orderInfo = "partner=" + "\"" + PARTNER + "\""; // 簽約賣家支付寶賬號 orderInfo += "&seller_id=" + "\"" + SELLER + "\""; // 商戶網站唯一訂單號 orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\""; // 商品名稱 orderInfo += "&subject=" + "\"" + subject + "\""; // 商品詳情 orderInfo += "&body=" + "\"" + body + "\""; // 商品金額 orderInfo += "&total_fee=" + "\"" + price + "\""; // 伺服器非同步通知頁面路徑 orderInfo += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\""; // 服務介面名稱, 固定值 orderInfo += "&service=\"mobile.securitypay.pay\""; // 支付型別, 固定值 orderInfo += "&payment_type=\"1\""; // 引數編碼, 固定值 orderInfo += "&_input_charset=\"utf-8\""; // 設定未付款交易的超時時間 // 預設30分鐘,一旦超時,該筆交易就會自動被關閉。 // 取值範圍:1m~15d。 // m-分鐘,h-小時,d-天,1c-當天(無論交易何時建立,都在0點關閉)。 // 該引數數值不接受小數點,如1.5h,可轉換為90m。 orderInfo += "&it_b_pay=\"30m\""; // extern_token為經過快登授權獲取到的alipay_open_id,帶上此引數使用者將使用授權的賬戶進行支付 // orderInfo += "&extern_token=" + "\"" + extern_token + "\""; // 支付寶處理完請求後,當前頁面跳轉到商戶指定頁面的路徑,可空 orderInfo += "&return_url=\"m.alipay.com\""; // 呼叫銀行卡支付,需配置此引數,參與簽名, 固定值 (需要簽約《無線銀行卡快捷支付》才能使用) // orderInfo += "&paymethod=\"expressGateway\""; return orderInfo; }
接下來就是生成紅色邊框裡面的內容,這裡就是對上傳的引數進行簽名,注意這裡的簽名要放在我們自己的後臺服務端上進行,不能放在app端,demo裡面用了一個String sign = sign(orderInfo);方法得到簽名的內容。最後對這個簽名的內容進行URL的轉義,千萬不要忘記了,文件說明有說明注意看下圖的黑色標記,demo用了這個方法sign = URLEncoder.encode(sign, "UTF-8");得到轉義後的簽名
通過上面的2個步驟,我們得到了一個orderInfo 字串,是上傳的引數資訊。 還有一個sign,就是簽名,而且這個簽名做了轉義處理。但是這2個字串不符合我們上傳的格式啊,因為這2個字串還沒有拼接起來,所以最後要把這2個字串拼接得到一個PayInfo字串
String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
這個getSignType()方法也很簡單,就是加上“RSA”即可,如下
private String getSignType() {
return "sign_type=\"RSA\"";
}
可以看到,走到這裡,這個payInfo就符合格式了,也就是最後呼叫支付寶Api的引數,如下程式碼。
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 構造PayTask 物件
PayTask alipay = new PayTask(PayDemoActivity.this);
// 呼叫支付介面,獲取支付結果
String result = alipay.pay(payInfo, true);//payInfo就是我們通過上面2個步驟得到的字串,這裡當成引數傳入
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必須非同步呼叫
Thread payThread = new Thread(payRunnable);
payThread.start();
以上就是移動支付,關於支付程式碼的一些個人總結,大家可以結合官方程式碼看看
官方的demo點選下載,可以結合程式碼看看,整體思路和邏輯就更清楚了。
二、微信移動支付
首先當然去看官方文件了,連結如下
接入的前期準備也不說,這裡只說邏輯思路,微信支付需要注意的事項
1、提交和返回資料都為XML格式,根節點名為xml。
2、採用POST方法提交
3、簽名的引數,將集合M內非空引數值的引數按照引數名ASCII碼從小到大排序(字典序)
4、交易金額預設為人民幣交易,介面中引數支付金額單位為【分】,引數值不能帶小數。對賬單中的交易金額單位為【元】
5、我們可以使用傳統的httpClient傳送post請求,
byte[] buf = Util.httpPost(url, entity); //url就是請求的網路介面地址,entity就是根據需求封裝的xml格式的字串
String content = new String(buf); //服務端返回位元組陣列,我們再轉成字串,這個字串就是我們得到的響應資料
說清楚了注意事項,接下來理清一下支付的流程邏輯,其實很簡單,步驟如下
1、統一下單,商戶系統先呼叫該介面在微信支付服務後臺生成預支付交易單,
2、返回正確的預支付訂單號,在APP裡面調起支付介面。
那麼一個個來吧,先看統一下單,生成預支付訂單的文件,我們需要分析需要上傳哪些引數,
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
從上圖得知,最後的sign欄位裡面的資料就是微信支付接入的核心。那麼問題就是,這個簽名是怎麼來的?
文件裡面也說得非常清楚,其實就是2個步驟
第一步,設所有傳送或者接收到的資料為集合M,將集合M內非空引數值的引數按照引數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串stringA。
特別注意以下重要規則:
◆ 引數名ASCII碼從小到大排序(字典序);
◆ 如果引數的值為空不參與簽名;
◆ 引數名區分大小寫;
◆ 驗證呼叫返回或微信主動通知簽名時,傳送的sign引數不參與簽名,將生成的簽名與該sign值作校驗。
◆ 微信介面可能增加欄位,驗證簽名時必須支援增加的擴充套件欄位
第二步,在stringA最後拼接上key得到stringSignTemp字串,並對stringSignTemp進行MD5運算,再將得到的字串所有字元轉換為大寫,得到sign值signValue。
我們看看上面的2個步驟是怎麼通過程式碼來實現的,demo裡首先走了這一句 ,
String entity = genProductArgs(); //這個方法的結果也就是說上面圖片所示的全部內容,包括了簽名。我們看看這個方法是怎麼實現的
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));
packageParams.add(new BasicNameValuePair("body", "APP pay test"));
packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
packageParams.add(new BasicNameValuePair("notify_url", "http://121.40.35.3/test"));
packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo()));
packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1"));
packageParams.add(new BasicNameValuePair("total_fee", "1"));
packageParams.add(new BasicNameValuePair("trade_type", "APP"));
上面的程式碼,就是把紅色方框裡面的我們需要的上傳引數放到一個List集合packageParams 裡面,這個集合的所有引數也就是生成預支付訂單號所需要的引數(注意,這個集合裡面add 的BaseNameValuePair的引數順序不能亂寫,需要按引數名ASCII碼從小到大排序,比如appid引數需要放第1位,body就需要跟在第2位新增進去,mcn_id就是第3位新增,為什麼要這麼做,因為這個集合裡的內容是需要簽名的,而簽名的其中一個要求就是引數名ASCII碼從小到大排序,這個很關鍵),那麼這個集合有什麼用,當然就是用來簽名,這個思路跟支付寶設計其實是一樣的,所有上傳引數封裝好,接下來還有藍色方框裡面的內容需要生成,程式碼走了這句
String sign = genPackageSign(packageParams); //這一句就是把所有資料進行簽名
我們看看這個 genPackageSign()簽名方法是如何實現的
private String genPackageSign(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < params.size(); i++) {
sb.append(params.get(i).getName());
sb.append('=');
sb.append(params.get(i).getValue()); //對引數按照key=value的格式組合 所以裡面的引數排序一定要先排好,順利不能亂
sb.append('&');
}
sb.append("key=");
sb.append(Constants.API_KEY);
String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
return packageSign; //在stringA最後拼接上key得到stringSignTemp字串,並對stringSignTemp進行MD5運算,再將得到的字串所有字元轉換為大寫
}
可以看到,這個方法就是簽名演算法的具體實現,邏輯上並不難。最後得到的這個結果是個字串,也就是sing欄位裡面的值,所以我們需要把它新增到上傳的集合裡面,所以程式繼續走下面一句
packageParams.add(new BasicNameValuePair("sign", sign));
到這裡,這個packageParams 就是我們所有要上傳的資料裡,但是它不是xml格式,接下來就要走這個方法
String xmlstring =toXml(packageParams);這個方法就是把集合裡面的資料封裝成xml的格式,我們來看看這個方法如何實現
private String toXml(List<NameValuePair> params) {
StringBuilder sb = new StringBuilder();
sb.append("<xml>");
for (int i = 0; i < params.size(); i++) {
sb.append("<"+params.get(i).getName()+">");
sb.append(params.get(i).getValue());
sb.append("</"+params.get(i).getName()+">");
}
sb.append("</xml>");
return sb.toString();
}
其實很簡單,迴圈遍歷整個集合,分別把name 和value組合即可。最後得到的xmlstring 字串就要上傳的字串,也就是entity的值,接下來直接走
byte[] buf = Util.httpPost(url, entity) ; //這個entity就是上傳的xml字串,裡面包含了所有引數和簽名欄位
String content = new String(buf); //這個content 就是得到了微信後臺伺服器返回的所有引數
接下來我們看程式走這一句
Map<String,String> xml=decodeXml(content); 就是把資料通過android的xml解析,封裝到一個map裡面
最後把這個map再賦值給resultunifiedorde,這個resultunifiedorder也是一個map。問題來了,這個resultunifiedorde有什麼用?裡面有個欄位prepay_id就是支付訂單號,調微信支付的介面,其中的一個欄位的值就是它了,總結:前面的這麼多步驟,其實核心就是一個 ,得到預支付訂單號。
拿到了預支付訂單號,接下來就是走支付介面,需要的引數如下
我們看到,這裡呼叫介面,最後的一個引數要又是sign,好吧,其實又封裝sign欄位之前的所有欄位來生成簽名,程式碼如下
private void genPayReq() {
req.appId = Constants.APP_ID;
req.partnerId = Constants.MCH_ID;
req.prepayId = resultunifiedorder.get("prepay_id");
//req.packageValue = "prepay_id="+resultunifiedorder.get("prepay_id");
/**
* 這裡的package引數值必須是Sign=WXPay,否則IOS端調不起微信支付,
* (引數值是"prepay_id="+resultunifiedorder.get("prepay_id")的時候Android可以,IOS不可以)
*/
req.packageValue = "Sign=WXPay";
req.nonceStr = genNonceStr();
req.timeStamp = String.valueOf(genTimeStamp())
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
req.sign = genAppSign(signParams)//這裡就是把之前的引數又封裝和簽名 也就是說demo裡面的 genAppSign 和genPackageSign 這2個方法其實都是一樣,不信可以去demo裡看看
}
注意 我們實際呼叫支付介面的引數 跟 生成預支付訂單號的引數 是不同的。但是生成簽名的過程都是一樣的!!!!
區別在於
(1)前者生成預支付訂單號封裝好所有的引數,需要組成xml格式字串,使用HttpCliet去傳送資料。
(2)而實際支付介面,我們需要封裝成一個PayReq 物件reg,這個reg物件裡面變數就是要上傳的引數,然後使用微信支付類即可,
IWXAPI msgApi = WXAPIFactory.createWXAPI(this, null);
msgApi.registerApp(Constants.APP_ID);
msgApi.sendReq(req);
不用再使用HttpClient
走到這裡,支付基本完成了,最後程式會執行我們自己專案裡面的wxapi包的WXEntryActivity.java 裡面的內容
以上的就是微信支付流程,需要大家去結合程式碼熟悉一下
最後最後的總結
1、支付寶和微信都需要對上傳引數做簽名,都是以key value排列,用&號連線多個引數, 具體上傳引數到各自的文件裡看即可。
2、參加簽名的引數,支付寶是無序,而微信有序。
3、支付寶只做了一次簽名,而微信其實做了2次簽名(第一次介面呼叫,使用了xml格式和HttpClient請求,第2次呼叫了msApi去發起實際支付)。
相關推薦
支付寶和微信移動支付的個人總結
今天在看了移動支付的文件,對整個流程都有了自己的理解,在這裡記錄下來自己的總結,把裡面的邏輯都整理一遍 一、支付寶支付 先去看官方的支付文件,連結如下 1、先說前期準備,關鍵就是要生成一對公鑰和私鑰,這個看官方文件,現在官方有個自動生成工具,其實挺方便的。注意的是如
支付寶和微信APP支付 java服務端程式碼
支付寶和微信支付的接入基本只需要看官方文件就能很好的弄明白,這裡我做記錄一些我在接入是寫demo 首先需要建立一個配置管理的類: public final class ZhifubaoConfig { /** * 應用號 */ publ
有了支付寶和微信為什麽要用聚合支付?
聚合支付 在街上 近期好多網友朋友咨詢聚合支付產品是什麽!我有支付寶跟微信了,要聚合支付有什麽用?今天這邊我們就針對這個問題做個闡述! 首先我們先來了解下什麽是聚合支付,聚合支付也稱第四方支付,它只是把支付寶、微信、銀行這些機構的資金通道做了集成,並
一個二維碼支援支付寶和微信支付(上)
開發十年,就只剩下這套Java開發體系了 >>> 一個二維碼同時支援微信和支付寶掃描的原理很簡單,就是中間做了一個跳轉,判斷使用者用的是什麼瀏覽器請求的即可。 這裡首先要說清楚的是支
JS處理支付寶和微信(同步提交/非同步提交)方式
PHP交流群:294088839 Python交流群:652376983 GO交流群:874512552 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title&
React Native (IOS和Android) 支付寶和微信支付整合實戰(支付寶Android篇)
序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 支付
React Native (IOS和Android) 支付寶和微信支付整合實戰(微信IOS篇)
序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 微信
JAVA支付寶和微信(APP支付,提現,退款)
公共引數圖表: 介面需要引數通知方式支付寶APP支付應用公鑰,應用私鑰非同步支付寶APP提現應用公鑰,應用私鑰,支付寶公鑰同步支付寶APP退款應用公鑰,應用私鑰,支付寶公鑰同步微信APP支付APPID,商戶號,api_key支付金鑰非同步微信APP提現APPID,
銀行紛紛斷開與支付機構直連,那支付寶和微信支付還能用嗎?
近日,包括中國銀行、交通銀行、中信銀行、光大銀行等在內多家銀行宣佈,將關閉原直連業務模式下與持牌第三方支付機構的合作通道,範圍包括協議支付、閘道器支付、付款業務及通過支付機構客戶備付金賬戶發生的代收付業務。有些人或許會擔心,在銀行關閉與支付機構的合作通道後,對我們使用微信、支付寶等三方支付平
來聊聊支付寶和微信支付
學習 不同 人的 一個人 同事 微信支付 就會 感覺 吃飯 最近支付寶像是瘋了一樣,開始瘋狂地推紅包活動。紅包,可以激發人的貪性。成千上萬的民眾,像瘋了一樣,開始義無反顧地加入了這場紅包盛宴中。 於是,我們的微博、朋友圈都被支付寶紅包占領了;去飯館吃飯,老板主動拿二維碼讓你
APP支付(支付寶和微信生成客戶端簽名及回撥驗籤)
<?php namespace Pn\Controller; use Think\Controller\RestController; class PayController extends RestController{ public function __
Android 支付寶和微信支付整合
場景 隨著移動支付的興起,在我們的app中,會經常有整合支付的需求.這時候一般都會採用微信和支付寶的sdk 來整合 支付寶支付 在使用支付寶支付的過程中,我們是在伺服器端生成訂單,客戶端訪問介面,得到訂單資訊.然後調起支付,支付成功後支付寶會分別 非同步呼叫伺服器端
React Native (IOS和Android) 支付寶和微信支付整合實戰(微信支付服務端篇)
序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 微信
React Native (IOS和Android) 支付寶和微信支付整合實戰(支付寶服務端篇)
序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 支
支付寶、微信sdk支付流程模擬
今天和同事閒聊的時候,聊到對接支付寶和微信sdk的事情,聊完以後興致未盡。順便去網上搜了一下,怎樣做一款sdk,網上的教程少的可憐,能搜到的也是好壞各異,參差不齊。遂下決心,敲一篇部落格,把sdk的實現流程講解一下。給迷茫中的小白一點思路。還是那句話,一萬個讀者
支付寶、微信、銀聯移動支付整合
一、支付寶移動支付 業務流程: SDK整合: 解壓介面壓縮檔案(檔名是 WS_MOBILE_PAY_SDK_BASE.zip),找到 IOS 的壓縮檔案(檔名是支付寶移動支付 SDK 標準版(iOS).zip)。 匯入程式碼 步驟1
spring_boot_pay支付寶,微信,銀聯支付詳細代碼案例
fan target 簽名加密 china 整合 提示 業務 rom sig spring-boot-pay 支付服務:支付寶,微信,銀聯詳細代碼案例(除銀聯支付可以測試以外,支付寶和微信支付測試均需要企業認證,個人無法完成測試),項目啟動前請仔細閱讀 註意事項 。 友情
HBuilder基礎上APP呼叫支付寶、微信支付(PHP)
支付寶後端程式碼: /** * @param Request $request * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View * 訂單頁面支付(支付寶支付) *
關於微信公眾號支付 微信H5支付和微信APP支付的問題 (PHP)TP+VUE
話不多說 直接上原始碼 在寫支付之前一定要確定好微信要求配置的相關回調域名 安全支付域名還有雜七雜八的哪些地址都準備好了 要不然是沒法實現的 微信公眾平臺 微信商戶平臺 還有開發者平臺 什麼的 這點比較噁心 1.微信公眾號支付 公眾號支付和H5支付最大的不同就在於公眾號支付使用者有ope
微信掃碼支付和微信JSAPI支付
專案中用到了PC端掃碼支付和 微信公眾號的JSAPI支付,在此記錄, 以免小夥伴被網上的‘拿來主義’給誤導。 使用框架THINKPHP5, 類檔案儲存在extend/payment 資料夾內。 包含功能:掃碼支付(採用先生成預支付訂單,然後返回支付二維碼地址,在頁面上使用qrcode.js