API 金鑰驗證與存取

所有的 API 要求都必須採用 EAN 的簽章驗證方式。您必須將以共用密碼、API 金鑰,和目前 UNIX 時間戳記為依據的簽章雜湊,連同 CID 與 API 金鑰一起傳送。將此雜湊碼作為每個要求的簽章一般元素值傳送。

登入聯盟夥伴中心,並檢視 API 最上方功能表下的「金鑰詳細資料」可找到 API 金鑰的共用密碼。

開發時,您可以使用簽章產生器快速製作您自己的簽章值,以在我們的沙箱中測試要求,或驗證您的實作所建立的值。

只有先前建立的帳戶,才會繼續支援 IP 驗證

利用共用密碼取得驗證,並建立程式碼中的數位簽章

使用數位簽章時,系統將透過產生由 API 金鑰、API 使用者的共用密碼,以及 UNIX 時間戳記所組成的 MD5 雜湊,計算簽章的值。

系統接受時間戳記有合理的時差,容許時間戳記比伺服器時間戳記最多相差五分鐘。

EAN 會利用網路時間通訊協定 (NTP) 同步內部伺服器的時間。如果您也使用 NTP,應該不會發生時間同步問題。大部分的新型作業系統都支援此功能,或有類似的時間同步服務,請查看您的作業系統文件以了解詳細資訊。

大部分的程式設計語言會提供可用來產生簽章的某一版 `md5()` 函數版本。下列範例說明如何使用 PHP 來產生有效的簽章:

$apiKey = 'xxx-YourAPIkey-xxx'; $secret = 'xxYourSecretxx'; $timestamp = gmdate('U'); // 1427233130 (Tue, 24 Mar 2015 21:38:50 +0000) $sig = md5($apiKey . $secret . $timestamp);

下列的 URL 範例說明使用如何使用數位簽章將 REST 要求發送至 Hotel Version 3 服務:一個 API 金鑰、一個時間戳記和一個共用密碼:

http://api.ean.com/ean-services/rs/hotel/v3/avail? cid=[yourCID] &apiKey=[yourAPIKey] &sig=[youSigValue] &minorRev=[current minorRev #] &customerUserAgent=[xxx] &customerIpAddress=[xxx] &locale=en_US &currencyCode=USD &hotelId=201252

注意:時間戳記經常是產生數位簽章時發生錯誤的原因。請務必:

  • 使用 GMT 時間,而不要使用當地時間。
  • 使用秒數,而不要使用毫秒。(根據預設,有些系統會使用毫秒為單位傳回時間)。
  • 如果您傳送 sig 要求卻收到驗證錯誤,請使用錯誤訊息中傳回的 Server Info (伺服器資訊) 時間戳記來傳送另一個要求,讓您的時間與伺服器同步。例如:<ServerInfo serverTime="19:11:13.082-0500" timestamp="1311725473" instance="48" />
參數 說明
apiKey 客戶應用程式識別碼。此字串長度上限為 255 個字元,且不可包含空格或特殊字元。這是在註冊應用程式時,指派給您的唯一金鑰。
sig 用於提出要求的數位簽章是由 apiKey、共用密碼及時間戳記建立的 MD5 雜湊碼。

所有 sig 值的長度至少要有 32 個小寫字元,因此必要時可在最終值前面加上 0 來處理字串,或將所有字元都改成小寫。

若您收到驗證錯誤,或在產生數位簽章時發生其他問題,請將您的值與 EAN Sig 產生器的值比對檢查。

其他常見要求元素

檢閱每次呼叫資料所用的常見要求元素清單

程式碼範本

您可以透過任何程式語言傳送要求。下列資料為數種常用程式語言 (PHP、Python、Java、Ruby、Perl 及 C#) 的程式碼範本。每個範例都利用 API 金鑰 (apiKey) 及數位簽章 (sig) 傳送查詢參數並藉此取得資料。回應中的資料不會因為程式語言不同而進行轉換。

若要傳送不具有數位簽章的要求並使用您 API 帳戶中設定的 IP 驗證,請移除要求中的共用密碼及 Sig 處理流程。

PHP

所有 sig 值的長度至少要有 32 個字元,因此必要時可在最終值前面加上 0 來處理字串。

<?php $secret = 'xxYourSecretxx'; $host = 'http://api.ean.com/';  // build path $ver = 'v3/'; $method = 'list/'; $path = "ean-services/rs/hotel/{$ver}{$method}";  // query parameters $apiKey = '[YourAPIkey]'; $cid = '[yourCID]'; $minorRev = '[currentMinorRev]'; $customerUserAgent = 'Mozilla/4.0'; $customerIpAddress = '172.16.82.13'; $locale = 'en_US'; $currencyCode = 'USD'; $hotelId = '201252';  $timestamp = gmdate('U'); $sig = md5($apiKey . $secret . $timestamp);  $query = "?apikey={$apiKey}&cid={$cid}&sig={$sig}&minorRev={$minorRev}" . "&customerUserAgent={$customerUserAgent}&customerIpAddress={$customerIpAddress}" . "&locale={$locale}&currencyCode={$currencyCode}&hotelIdList={$hotelId}";  // initiate curl $ch = curl_init();  curl_setopt($ch, CURLOPT_URL, $host . $path . $query); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_setopt($ch, CURLOPT_HTTPHEADER,array('Accept:application/json')); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $data = curl_exec($ch); $headers = curl_getinfo($ch);  // close curl curl_close($ch);  // return XML data if ($headers['http_code'] != '200') {  echo "An error has occurred."; return false; } else {  echo $data;  return($data); } ?>

Python

若認證有效,呼叫會將 XML 裝載傳回至名為的 ‘xml.’ 的變數中。

所有 sig 值的長度至少要有 32 個字元,因此必要時可在最終值前面加上 0 來處理字串。

import urllib2 import md5 import time  service = 'http://api.ean.com/ean-services/rs/hotel/' version = 'v3/' method = 'list/' hotelId = '201252' otherElementsStr = 'cid=55505&minorRev=[x]&customerUserAgent=[xxx]&customerIpAddress=[xxx]&locale=en_US&currencyCode=USD'   apiKey = 'YourAPIkey' secret = 'YourSecret'  hash = md5.new() # seconds since GMT Epoch timestamp = str(int(time.time())) # print timestamp sig = md5.new(apiKey + secret + timestamp).hexdigest() url = service + version + method+ '?apiKey=' + apiKey + '&sig=' + sig + otherElementsStr + '&hotelIdList=' + hotelId # print url xml = urllib2.urlopen(url).read()  print xml

Java

下列 Java 範例說明如何透過 HTTP GET 執行資料的網頁服務要求。此項作業須透過由 Apache 軟體基金會提供的 HttpComponents 套件執行:

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;  import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient;  public class RestfulCallExample {   public static String service = "http://api.ean.com/ean-services/rs/hotel/";  public static String version = "v3/";  public static String method = "list";  public static String hotelId = "201252";  public static String otherElementsStr = "&cid=55505&minorRev=[x]" + "&customerUserAgent=[xxx]&customerIpAddress=[xxx]&locale=en_US&currencyCode=USD";  public static String apikey = "xxx-YourAPIkey-xxx";  public static String secret = "xxYourSecretxx";   public static void main(String[] args) throws NoSuchAlgorithmException {  MessageDigest md = MessageDigest.getInstance("MD5"); long timeInSeconds = (System.currentTimeMillis() / 1000); String input = apikey + secret + timeInSeconds; md.update(input.getBytes()); String sig = String.format("%032x", new BigInteger(1, md.digest()));  String url = service + version + method+ "?apikey=" + apikey  + "&sig=" + sig + otherElementsStr + "hotelIdList=" + hotelId; System.out.println("URL = " + url); DefaultHttpClient httpclient = new DefaultHttpClient();  // Create an HTTP GET request HttpGet httpget = new HttpGet(url);  // Execute the request httpget.getRequestLine(); HttpResponse response = null; try {  response = httpclient.execute(httpget); } catch (IOException e) {  e.printStackTrace(); return; }   HttpEntity entity = response.getEntity(); // Print the response System.out.println(response.getStatusLine());  if (entity != null) {  try { InputStream inputStream = entity.getContent(); // Process the response BufferedReader bufferedReader = new BufferedReader(  new InputStreamReader(inputStream)); String line; while ((line = bufferedReader.readLine()) != null) {  System.out.println(line); } bufferedReader.close();  } catch (IOException e) { e.printStackTrace();  } } // shut down the connection manager to free up system resources. httpclient.getConnectionManager().shutdown();  } }

Ruby

下列 Ruby 範本採用 Digest::MD5 產生數位簽章,並使用 Net::HTTP 傳送要求。

所有 sig 值的長度至少要有 32 個字元,因此必要時可在最終值前面加上 0 來處理字串。

require 'net/http' require 'digest/md5'  # hotelId to send hotelId = '201252'  #additional parameters set in a single string for brevity $otherElemntsStr = '&cid=55505&minorRev=[x]&customerUserAgent=[xxx]&customerIpAddress=[xxx]&locale=en_US&currencyCode=USD'   # API location PRODUCTION_ENDPOINT = 'api.ean.com/ean-services/rs/hotel/' PRODUCTION_PORT = 80  # Your credentials API_KEY = 'YourAPIkey' SHARED_SECRET = 'YourSecret' API_VERSION = 'v3'  current_time = Time.now timestamp = Time.now.to_i.to_s sig = Digest::MD5.hexdigest( API_KEY+SHARED_SECRET+timestamp )  request_url = "/#{API_VERSION}/list}?apiKey=#{API_KEY} & sig=#{sig} & #{otherElementsStr} & hotelIdList=#{hotelId}"  http = Net::HTTP.new( PRODUCTION_ENDPOINT , PRODUCTION_PORT ) http.start do |http| req = Net::HTTP::Get.new(request_url)  resp, data = http.request(req)  print data end

Perl

所有 sig 值的長度至少要有 32 個字元,因此必要時可在最終值前面加上 0 來處理字串。

# perl  use strict; # use LWP::Simple; use LWP::UserAgent; use Digest::MD5 qw(md5 md5_hex);  my $service = 'http://api.ean.com/ean-services/rs/hotel/'; my $method = 'list/'; my $version= 'v3/'; my $hotelId = '201252'; my $otherElemntsStr = '&cid=[xx]&minorRev=[x]&customerUserAgent=[xxx]&customerIpAddress=[xxx]&locale=en_US&currencyCode=USD';  # key and shared secret obtained from registering application my $apiKey = 'YourAPIkey'; my $secret = 'YourSecret';  my $timestamp = time; #above timestamp needs to be created in PERL !!! Placeholder my $sig = md5_hex($apiKey . $secret . $timestamp);  # print $timestamp,"", $sig, "\n";  my $ua = new LWP::UserAgent; $ua->timeout(120);  my $url=$service . $version . $method. '?apiKey=' . $apiKey . '&sig=' . $sig . $otherElementsStr . '&hotelIdList=' . $hotelId; # print $url, "\n";  my $request = new HTTP::Request('GET', $url); my $response = $ua->request($request); my $xml = $response->content(); print $xml,"\n";

C#

下列 C# 範本採用 HttpWebRequest 及 HttpWebResponse。

所有 sig 值的長度至少要有 32 個字元,因此必要時可在最終值前面加上 0 來處理字串。

using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Net; using System.Security.Cryptography;  namespace QuovaRESTSample { class Program { static void Main(string[] args) { string service = "http://api.ean.com/ean-services/rs/hotel/"; string version = "v3/"; string method = "list/"; string hotelId = "201252"; 	string otherElemntsStr = "&cid=[x]&minorRev=[x]&customerUserAgent=[xxx]&customerIpAddress=[xxx]&locale=en_US&currencyCode=USD"; string apiKey = "xxx-YourAPIkey-xxx"; string secret = "xxYourSecretxx"; string sig = MD5GenerateHash(apiKey + secret + (Int32)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds); string fullURL = service + version + method+ "?apiKey=" + apiKey + "&sig=" + sig + otherElementsStr + "&hotelIdList=" + hotelId;  // Create the web request HttpWebRequest request = WebRequest.Create(fullURL) as HttpWebRequest;  // Get response using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { // Get the response stream StreamReader reader = new StreamReader(response.GetResponseStream());  // Write response to the console Console.WriteLine(reader.ReadToEnd()); }  }  private static string MD5GenerateHash(string strInput) { // Create a new instance of the MD5CryptoServiceProvider object. MD5 md5Hasher = MD5.Create();  // Convert the input string to a byte array and compute the hash. byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(strInput));  // Create a new Stringbuilder to collect the bytes and create a string. StringBuilder sBuilder = new StringBuilder();  // Loop through each byte of the hashed data and format each one as a hexadecimal string. for (int nIndex = 0; nIndex < data.Length; ++nIndex) { sBuilder.Append(data[nIndex].ToString("x2")); }  // Return the hexadecimal string. return sBuilder.ToString(); } } }