1. 程式人生 > >支付寶和微信移動支付的個人總結

支付寶和微信移動支付的個人總結

今天在看了移動支付的文件,對整個流程都有了自己的理解,在這裡記錄下來自己的總結,把裡面的邏輯都整理一遍

一、支付寶支付

先去看官方的支付文件,連結如下

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 (IOSAndroid) 支付支付整合實戰(支付Android篇)

序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 支付

React Native (IOSAndroid) 支付支付整合實戰(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 (IOSAndroid) 支付支付整合實戰(支付服務端篇)

序言:React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。 微信

React Native (IOSAndroid) 支付支付整合實戰(支付服務端篇)

序言: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