1. 程式人生 > >回顧篇:淘寶API web開發二 呼叫API

回顧篇:淘寶API web開發二 呼叫API

上一篇已經說明了如何引導使用者授權登入,獲取access_token。這樣,我們就可以正式呼叫API了。

淘寶提供了兩種呼叫方法,一種為http呼叫方法,一種為https免籤呼叫方式。因為專案用的是第一種方法,那麼在這裡,我們就只介紹http的呼叫方法。

淘寶API採用REST風格,我們需要按照淘寶開發平臺的規範拼裝一個正確的URL,通過HTTP請求到http://gw.api.taobao.com/router/rest(測試環境為http://gw.api.tbsandbox.com/router/rest),就可以獲取到自己需要的資料。

呼叫API時,需要傳入系統引數和應用引數。

系統引數如下:

名稱

型別

是否必須

描述

method

string

Y

API介面名稱
timestamp

string

Y

時間戳,格式為yyyy-mm-dd HH:mm:ss,例如:2013-05-06 13:52:03。淘寶API服務端允許客戶端請求時間誤差為6分鐘。
format

string

N

可選,指定響應格式。預設xml,目前支援格式為xml,json
app_key

string

Y

TOP分配給應用的AppKey ,建立應用時可獲得
v

string

Y

API協議版本,可選值:2.0。
sign

string

Y

對 API 輸入引數進行 md5 加密獲得,下面會介紹到sign
sign_method

string

Y

引數的加密方法選擇,可選值是:md5,hmac
session

string

N

TOP分配給使用者的SessionKey(或 Access Token),通過登陸授權獲取(可參考上一篇博文) 。API 文件上 “API使用者授權型別” 標識為“需要”的,呼叫時均要傳該引數
應用引數是根據不同的API而不同的,我們就以taobao.trades.sold.increment.get(增量訂單)為例,來做說明。

應用引數如下:

名稱

型別

是否必須

描述

fields

Field List

Y

獲取到資料後,需要返回的欄位。
示例值:
tid,type,status,modified,orders.title,orders.oid
更多值請參考http://api.taobao.com/apidoc/api.htm?spm=0.0.0.0.yd3ygq&path=cid:5-apiId:128
start_modified

Date

Y

查詢修改開始時間(修改時間跨度不能大於一天)。格式:yyyy-MM-dd HH:mm:ss
end_modified

Date

Y

查詢修改結束時間,必須大於修改開始時間(修改時間跨度不能大於一天),格式:yyyy-MM-dd HH:mm:ss。
status

string

N

交易狀態,預設查詢所有交易狀態的資料,除了預設值外每次只能查詢一種狀態。可選值如 TRADE_NO_CREATE_PAY(沒有建立支付寶交易) WAIT_BUYER_PAY(等待買家付款) 等。
type

string

N

交易型別列表,同時查詢多種交易型別可用逗號分隔。默認同時查詢guarantee_trade,auto_delivery,ec,code,step的5種交易型別的資料。
ext_type

string

N

可選值有ershou(二手市場的訂單),service(商城服務子訂單)mark(雙十一大促活動異常訂單)作為擴充套件型別篩選只能做單個ext_type查詢,不能全部查詢所有的ext_type型別
tag

string

N

賣家對交易的自定義分組標籤,目前可選值為:time_card(點卡軟體代充),fee_card(話費軟體代充)
page_no

Number

N

頁碼。取值範圍:大於零的整數;預設值:1。注:必須採用倒序的分頁方式(從最後一頁往回取)才能避免漏單問題。
page_size

Number

N

每頁條數。取值範圍:1~100,預設值:40。
use_has_next

Boolean

N

是否啟用has_next的分頁方式,如果指定true,則返回的結果中不包含總記錄數,但是會新增一個是否存在下一頁的的欄位,通過此種方式獲取增量交易,效率在原有的基礎上有80%的提升

在系統引數中,我們需要傳入引數的簽名驗證sign,淘寶開發平臺伺服器需要對該請求引數進行驗證是否合法,方法如下:

根據引數名稱(除簽名和圖片)將所有請求引數按照字母先後順序排序:key + value.....key + value,再將應用的secretKey加在該字串的前後兩端。

例如,secretKey=4,將引數為foo=1,bar=2,baz=3排序為bar=2,baz=3,foo=1,引數名和引數值連線後,拼接成字串 4bar2baz3foo14

然後再將拼接的字串採用MD5或者HMAC加密,將加密結果轉換為32位大寫字串。

最後,我們就可以將所有的引數拼接好,使用CURL庫將引數POST到淘寶開發平臺,獲取我們需要的資料了。

具體程式碼如下:

設定請求引數的應用級引數 webERP / api / taobao / common / taobaoRequest.php

<?php 
	/**
	* 這個檔案包含 taobaoRequest類
	*/
	/**
	* taobaoRequest 設定請求引數的應用級引數
	*/
	class taobaoRequest{
		/**
		* @var array 應用級引數陣列
		*/
		protected $apiParams = array();

		/**
		* @var string 使用的介面名稱
		*/
		protected $apiMethod;

		/**
		* 設定使用介面的名稱
		* @param string $value 介面名稱
		*/
		function setApiMethod( $value ){

			$this->apiMethod = empty($value)? '' : $value;
		
		}

		/**
		* 返回使用的介面名稱
		* @return 使用的介面名稱
		*/
		function getApiMethod(){

			return $this->apiMethod;
		}

		/**
		* 設定應用引數值,為了適用不同的介面,引數名需要自己傳入
		* @param string $key 應用引數的引數名,不同介面引數名會有所不同
		* @param string $value 引數的值
		*/
		public function set( $key, $value ){

			$this->apiParams[$key] = $value;

		}

		/**
		* 獲取指定的應用引數值
		* @param string $key 指定的引數名
		* @return string 對應的引數值
		*/
		public function get( $key ){

			return isset($this->apiParams[$key])? $this->apiParams[$key] : null;

		}

		/**
		* 獲取按引數名稱排序後的應用級引數陣列
		* @return array 應用級引數陣列
		*/
		public function getApiParams(){
			//將引數按字母排序
			ksort($this->apiParams);

			if( $this->apiParams ){

				return $this->apiParams;

			}else{
				return [];
			}
		}

		/**
		* 有些介面需要傳送附件,獲取檔案的base64編碼
		* @param string 檔案路徑
		* @return 檔案內容的編碼
		*/
		public function fileHandle( $file ){

			//php curl的附件傳送機制中,需要在檔案路徑前加上@
			if(substr($file, 0, 1) == '@'){

				$file = substr($file, 1);
				$file = base64_encode( file_get_contents($file) );

			}

			return $file;

		}


	}
?>
呼叫API介面 webERP / api / taobao / common / taobaoClient.php
<?php
/**
* 這個檔案包含taobaoClient類
*/
/**
* taobaoClient類 根據引數生成簽名
* 將引數拼接成指定規則的URL,通過HTTP請求到淘寶開發平臺
* 解析返回的資料
*/

	class taobaoClient{

		/**
		*@var string 應用的appkey
		*/
		public $appKey;


		/**
		*@var string 應用的secretKey
		*/
		public $secretKey;

		/**
		 *@var string HTTP請求的地址
		*/
		public $gateWayUrl = "http://gw.api.taobao.com/router/rest";

		/**
		 * @var string 請求的系統引數,預設值2.0
		*/
		public $apiVersion = '2.0';

		/**
		* 拼裝請求引數拼,通過HTTP請求請求資料
		* @param taobaoRequest $request taobaoRequest類物件
		* @param string $session 訪問令牌ACCESS TOKEN
		*/
		public function execute(taobaoRequest $request, $session = null){

			$result = new stdClass();//保留類,存放返回的錯誤資訊

			//設定系統引數
			$sysParams['method'] = $request->getApiMethod();//API介面名稱

			if($session != null){

				$sysParams['session'] = $session;//access token

			}

			$sysParams['timestamp'] = date('Y-m-d H:i:s');//時間戳
			$sysParams['format'] = 'json'; // 指定響應格式,支援的格式有json,xml
			$sysParams['app_key'] = $this->$appKey;
			$sysParams['v'] = $this->apiVersion;
			$sysParams['sign_method'] = 'md5';//引數的加密方法選擇,可選值是:md5,hmac

			//應用級引數
			$apiParams = array();
			$apiParams = $request->getApiParams();

			//系統引數,簽名驗證sign
			$sysParams['sign'] = $this->generateSign(array_merge($sysParams, $apiParams ));

			$requestUrl = $this->gateWayUrl . '?' . http_build_query($sysParams);

			//獲取資料
			try{

				$resp = $this->curl($requestUrl, $apiParams);

			}catch(Exception $e){

				$result->code = $e->getcode();
				$result->zh_desc = "curl傳送http請求失敗";
				$result->en_desc = $e->getMessge();

			}

			//解析返回結果
			$respObject = json_decode($resp); // 解析json格式資料
			$respWellFormed = false;

			if( null != $respObject){

				$respWellFormed = true;

				foreach ( $respObject as $propKey => $propValue) {
					$respObject = $propValue;
				}

			}

			if(false ===  $respWellFormed){
				$result->code = 1;
            	$result->zh_desc = "api返回資料錯誤或程式無法解析返回引數";
            	$result->en_desc = "HTTP_RESPONSE_NOT_WELL_FORMED";
            	return $result;
			}

			return $respObject;


		}

		/**
		* 生成驗證簽名sign
		* 根據引數名稱(除簽名和圖片)將所有請求引數按照字母先後順序排序,
		* 再將應用的secretKey加在該字串的前後兩端,
		* 然後再將拼接的字串採用MD5或者HMAC加密,將加密結果轉換為32位大寫字串。
		* @param array 請求引數陣列
		* @return array 加密後的簽名
		*/
		private function generateSign( $params ){

			if( $params != null){

				ksort($params);

				$stringToBeSigned = $this->secretKey;

				foreach ($params as $key => $value) {

					$stringToBeSigned .= "$key$value";

				}

				$stringToBeSigned .= $this->secretKey;

			}else{

				$stringToBeSigned = $this->secretKey;

				$stringToBeSigned .= $this->secretKey;

			}

			//注意:根據系統引數sign_method設定的加密的方法
			return strtoupper( md5($stringToBeSigned) );

		}

		/**
		* 使用CURL庫,做HTTP請求資料
		* @param string 請求訪問的地址
		* @param array 訪問所需的應用級引數
		* @return json 返回的資料結果
		*/
		public function curl($url, $postFields = null){

			//使用curl庫
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $url);//需要獲取的URL
			curl_setopt($ch, CURLOPT_FAILONERROR, false);//不顯示HTTP狀態碼
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);//獲取的資訊以檔案流的形式返回

			//https免籤呼叫方式
			if( strlen($url) >5 && strtolower(substr($url, 0, 5)) == 'https'){

				curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, fasle);//終止從伺服器端進行驗證
				curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

			}

			//
			if( isset($postFields) && 0 > count($postFields) ){

				curl_setopt($ch, CURLOPT_POST, ture);//以POST方式傳送

				$postMultipart = false;

				//判斷是否有附件傳送
				foreach ($postFields as $key => $value) {

					if( '@' == substr($value, 0, 1)){
						$postMultipart = true;
						break;

					}
				}

				unset($key, $value);

				if( $postMultipart ){

					curl_setopt($ch, CURLOPT_POSTFIELD, $postFields);
				
				}else{

					curl_setopt($ch, CURLOPT_POSTFIELD, http_build_query($postFields));

				}

			}

			$response = curl_exec($ch);

			if( curl_errno($ch) ){

				throw new Exception(curl_errno($ch), 0);

			}else{

				$httpStatusCode = curl_getinfo($ch, CURLOPT_HTTP_CODE);

				if(200 != $httpStatusCode){
					throw new Exception($response, $httpStatusCode);
				}
			
			}

			curl_close($ch);
			return $response;

		}



	
	}
 ?>

現在來測試呼叫taobao.trade.sold.increment.get介面,程式碼如下webERP / api / taobao / tradeSoldIncrementGet.php
<?php
	
	//測試呼叫介面 taobao.trade.sold.increment.get
	date_default_timezone_set('PRC');//設定時區

	//結束時間 預設當天
	$end_date = date('Y-m-d 23:59:59');

	//開始時間前一天
	$start_date = date('Y-m-d 23:59:59', strtotime("$end_date -1 day"));

	require_once 'common/taobaoConfig.php';
	require_once 'common/taobaoRequest.php';

	$request = new taobaoRequest();
	//呼叫介面taobao.trades.sold.increment.get
	$request->setApiMethod('taobao.trades.sold.increment.get');

	//根據淘寶要求的該介面的應用引數,設定各個引數值
	$fields = 'seller_nick, buyer_nick, title, type, created, tid,buyer_rate,can_rate,status, payment, discount_fee, adjust_fee, post_fee, total_fee, pay_time, end_time, modified, consign_time, buyer_obtain_point_fee, point_fee, real_point_fee, received_payment,num, price, cod_fee, cod_status, shipping_type, receiver_name, receiver_state, receiver_city, receiver_district, receiver_address, receiver_zip, receiver_mobile, receiver_phone,alipay_id,alipay_no,has_buyer_message,credit_card_fee,step_trade_status,step_paid_fee,mark_desc,trade_source,seller_flag,is_part_consign, orders.title, orders.price, orders.num, orders.sku_id, orders.refund_status, orders.status, orders.oid, orders.total_fee, orders.payment, orders.discount_fee, orders.adjust_fee, orders.sku_properties_name, orders.outer_sku_id, orders.refund_id,orders.end_time,orders.consign_time,orders.shipping_type,orders.logistics_company,orders.invoice_no';

    $request->set('fields',$fields);

    $request->set('start_modified',$start_date);
    $request->set('end_modified',$end_date);

    $page_size = 20;
    $request->set('page_size', $page_size);//每頁20條記錄

    $request->set('use_has_next', 'true');//分頁獲取

    $page_no = 1;

    while(true){

    	$request->set('page_no', $page_no);//獲取第page_no頁資料

    	$response = $taobao->execute($request,$access_token);

    	echo '<pre>';
    	var_dump($response);//輸出返回結果,可根據自己需要做其他操作
    	//獲取錯誤,停止獲取
    	if( isset($response->code) ){
    		
    		break;
    	}

    	//判斷是否還存在下一頁,如果還存在,則繼續請求資料
    	if( $response->has_next ){
    		$page_no++;

    	}else{
    		break;
    	}

    }

 ?>