感谢您的反馈!
APIs in the URL AliExpress Open Platform need to be invoked based on the Hypertext Transfer Protocol (HTTP). To invoke a specific API: The developer (such as the ISV) has two choices:
The API invocation process mainly has the following steps.
- Fill in parameters.
- Generate a signature.
- Encapsulate an HTTP request.
- Initiate the HTTP request
- Receive an HTTP response.
- Interpret JSON/XML results
Based on the service URL used to invoke APIs, the AliExpress open platform currently provides two environments for ISVs: formal environment, and overseas environment. The seller could initiate a performance test before deciding which URL to choose.
Invocation Environment | Service URL (HTTP) | Service URL (HTTPS) |
---|---|---|
Overseas environment(US) | http://api.taobao.com/router/rest | https://api.taobao.com/router/rest |
Overseas environment(EU) | ||
Overseas environment(Russia) |
Public parameters need to be set for every API. The following table lists all public parameters.
Parameter Name | Parameter Type | Mandatory or Optional | Parameter Description |
---|---|---|---|
method | String | Mandatory | Indicates the API name. |
app_key | String | Mandatory | Indicates the AppKey allocated by the TOP to an application. An ISV can choose Open Platform Console > Application Management > Overview to check the AppKey and AppSecret of the formal environment. |
session | String | Mandatory | Indicates the authorization granted by the TOP to an application after a user logs in and grants authorization successfully. For details, click here |
timestamp | String | Mandatory | Indicates the time stamp in the format of yyyy-MM-dd HH:mm: ss and in the time zone of GMT+8. For example, 2016-01-01 12:00:00. The Taobao API server allows a maximum time error of 10 minutes for a request from a client. |
format | String | Optional | Indicates the response format. The default value is XML. The value can be set to XML or JSON. |
v | String | Mandatory | Indicates the API protocol version. The value can be set to 2.0. |
simplify | Boolean | Optional | Indicates whether the simplified JSON return format is used. This parameter is valid only if the format is set to JSON. The default value is false. |
sign_method | String | Mandatory | Indicates the signature digest algorithm. The value can be set to hmac or md5. |
sign | String | Mandatory | Indicates the obtained signature of API input parameters. For details about the signature algorithm, see the following description. |
Besides public parameters, for each specific API, there are some input parameters.
To prevent data from being tampered maliciously by a hacker during API invocation, each request for API invocation must carry a signature. The TOP server verifies the signature based on request parameters and rejects the request carrying an invalid signature. Currently, the TOP supports two signature algorithms: MD5(sign_method=md5) and HMAC_MD5(sign_method=hmac). The signature process is generally described as follows:
Note: Both MD5 and HMAC_MD5 digest algorithms produce a 128-bit value represented in hexadecimal. As each hexadecimal character represents four bits, the length of the signature character string is fixed to 32 hexadecimal characters.
public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException {
//Step 1: Check whether parameters have been sorted.
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
//Step 2: Splice all sorted parameter names and values together.
StringBuilder query = new StringBuilder();
if (Constants.SIGN_METHOD_MD5.equals(signMethod)) {
query.append(secret);
}
for (String key : keys) {
String value = params.get(key);
if (StringUtils.areNotEmpty(key, value)) {
query.append(key).append(value);
}
}
//Step 3: Use the MD5 or HMAC_MD5 algorithm to encrypt the spliced character string.
byte[] bytes;
if (Constants.SIGN_METHOD_HMAC.equals(signMethod)) {
bytes = encryptHMAC(query.toString(), secret);
} else {
query.append(secret);
bytes = encryptMD5(query.toString());
}
//Step 4: Convert binary characters into capitalized hexadecimal characters. (A correct signature must be a character string consisting of 32 capitalized hexadecimal characters. This step is performed as required.)
//return byte2hex(bytes);
}
public static byte[] encryptHMAC(String data, String secret) throws IOException {
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), "HmacMD5");
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8));
} catch (GeneralSecurityException gse) {
throw new IOException(gse.toString());
}
return bytes;
}
public static byte[] encryptMD5(String data) throws IOException {
return encryptMD5(data.getBytes(Constants.CHARSET_UTF8));
}
public static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
public static string SignTopRequest(IDictionary<string, string> parameters, string secret, string signMethod)
{
//Step 1: Sort the dictionary based on the alphabetical order of Key.
IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal);
IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
//Step 2: Splice all sorted parameter names and values together.
StringBuilder query = new StringBuilder();
if (Constants.SIGN_METHOD_MD5.Equals(signMethod))
{
query.Append(secret);
}
while (dem.MoveNext())
{
string key = dem.Current.Key;
string value = dem.Current.Value;
if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
{
query.Append(key).Append(value);
}
}
//Step 3: Use the MD5 or HMAC_MD5 algorithm to encrypt the spliced character string.
byte[] bytes;
if (Constants.SIGN_METHOD_HMAC.Equals(signMethod))
{
HMACMD5 hmac = new HMACMD5(Encoding.UTF8.GetBytes(secret));
bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
}
else
{
query.Append(secret);
MD5 md5 = MD5.Create();
bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString()));
}
//Step 4: Convert binary characters into capitalized hexadecimal characters.
StringBuilder result = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
result.Append(bytes[i].ToString("X2"));
}
return result.ToString();
}
For details about the signature sample code in other languages, see the source code of the TOP official SDK.
The following uses the API Aliexpress.solution.order.fulfill(order fulfillment) as an example. The procedure for invoking this API is as follows:
Public parameters:
Service parameters:
app_key12345678formatjsonlogisitics_noES2019COM0000123456methodaliexpress.solution.order.fulfillout_ref1000006270175804send_typeallservice_namSPAIN_LOCAL_CORREOSesessiontestsign_methodmd5timestamp2019-01-01 12:00:00v2.0
Assume that secret of the application is helloworld. The obtained signature is as follows: hex(md5(helloworld+Sorted and spliced parameter names and values+helloworld)) = “F7A5E0B28DEFFE9E1E6E5C0E8B0530EC”().
Perform URL encoding for all parameter names and values based on the UTF-8 encoding. The sequence of parameters can be random, but the sign parameter must be included. Then, use the GET or POST method (containing parameters of the byte[] type) to initiate the HTTP request. For example:
http://gw.api.taobao.com/router/rest?method=aliexpress.solution.order.fulfill&app_key=12345678&session=test×tamp=2019-01-01 12:00:00&format=json&v=2.0&sign_method=md5&logistics_no=ES2019COM0000123456&out_ref=1000006270175804&send_type=all&service_name=SPAIN_LOCAL_CORREOS&sign=F7A5E0B28DEFFE9E1E6E5C0E8B0530EC
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class AffApiTest {
/** MD5 signature */
private static final String SIGN_METHOD_MD5 = "md5";
/** HMAC signature */
private static final String SIGN_METHOD_HMAC = "hmac";
/** HMAC-SHA256 signature */
private static final String SIGN_METHOD_HMAC_SHA256 = "hmac-sha256";
/** UTF-8 Character set **/
public static final String CHARSET_UTF8 = "UTF-8";
public static void main(String[] args) throws IOException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Map<String, String> paramMap = new HashMap<>();
paramMap.put("timestamp", sdf.format(Calendar.getInstance().getTime()));
paramMap.put("v", "2.0");
paramMap.put("method", "aliexpress.affiliate.category.get");
paramMap.put("partner_id", "top-apitools");
paramMap.put("format", "json");
paramMap.put("app_key", "your appkey");
paramMap.put("sign_method", "hmac");
String sign = signTopRequest(paramMap, "your secret", SIGN_METHOD_HMAC);
String resultget = sendGet("http://api.taobao.com/router/rest",
buildQuery(paramMap, "UTF-8") + "&sign=" + sign);
System.out.println(resultget);
}
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
System.out.println(urlNameString);
URL realUrl = new URL(urlNameString);
//connect with URL
URLConnection connection = realUrl.openConnection();
//create connection
connection.connect();
//define BufferedReader to get response of URL
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("An exception occurred when sending a GET request!" + e);
e.printStackTrace();
}
//use finally block to close instream
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
public static String buildQuery(Map<String, String> params, String charset) throws IOException {
if (params == null || params.isEmpty()) {
return null;
}
StringBuilder query = new StringBuilder();
Set<Entry<String, String>> entries = params.entrySet();
boolean hasParam = false;
for (Entry<String, String> entry : entries) {
String name = entry.getKey();
String value = entry.getValue();
//Ignore parameters whose parameter name or parameter value is empty
if (areNotEmpty(name, value)) {
if (hasParam) {
query.append("&");
} else {
hasParam = true;
}
query.append(name).append("=").append(URLEncoder.encode(value, charset));
}
}
return query.toString();
}
/**
* make signature
*
* @param params All character TOP request parameters
* @param secret signing secret
* @param signMethod signMethod support:empty(old md5)、md5, hmac_md5
* @return signature
*/
public static String signTopRequest(Map<String, String> params, String secret, String signMethod)
throws IOException {
//1step:Check if the parameters are sorted
String[] keys = params.keySet().toArray(new String[0]);
Arrays.sort(keys);
//2step:String together all parameter names and parameter values
StringBuilder query = new StringBuilder();
if (SIGN_METHOD_MD5.equals(signMethod)) {
query.append(secret);
}
for (String key : keys) {
String value = params.get(key);
if (areNotEmpty(key, value)) {
query.append(key).append(value);
}
}
//3step:Use MD5/HMAC encryption
byte[] bytes;
if (SIGN_METHOD_HMAC.equals(signMethod)) {
bytes = encryptHMAC(query.toString(), secret);
} else if (SIGN_METHOD_HMAC_SHA256.equals(signMethod)) {
bytes = encryptHMACSHA256(query.toString(), secret);
} else {
query.append(secret);
bytes = encryptMD5(query.toString());
}
//4step:Convert binary to uppercase hexadecimal
return byte2hex(bytes);
}
private static byte[] encryptHMACSHA256(String data, String secret) throws IOException {
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), "HmacSHA256");
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
bytes = mac.doFinal(data.getBytes(CHARSET_UTF8));
} catch (GeneralSecurityException gse) {
throw new IOException(gse.toString());
}
return bytes;
}
private static byte[] encryptHMAC(String data, String secret) throws IOException {
byte[] bytes = null;
try {
SecretKey secretKey = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), "HmacMD5");
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
bytes = mac.doFinal(data.getBytes(CHARSET_UTF8));
} catch (GeneralSecurityException gse) {
throw new IOException(gse.toString());
}
return bytes;
}
/**
* After encoding the string with UTF-8, use MD5 for digest
*/
public static byte[] encryptMD5(String data) throws IOException {
return encryptMD5(data.getBytes(CHARSET_UTF8));
}
/**
* MD5 digest of byte stream
*/
public static byte[] encryptMD5(byte[] data) throws IOException {
byte[] bytes = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
bytes = md.digest(data);
} catch (GeneralSecurityException gse) {
throw new IOException(gse.toString());
}
return bytes;
}
/**
* Convert byte stream to hexadecimal representation
*/
public static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
/**
* Check if the specified string list is not empty */
public static boolean areNotEmpty(String... values) {
boolean result = true;
if (values == null || values.length == 0) {
result = false;
} else {
for (String value : values) {
result &= !isEmpty(value);
}
}
return result;
}
/**
* Check whether the specified string is empty
* <ul>
* <li>SysUtils.isEmpty(null) = true</li>
* <li>SysUtils.isEmpty("") = true</li>
* <li>SysUtils.isEmpty(" ") = true</li>
* <li>SysUtils.isEmpty("abc") = false</li>
* </ul>
*
* @param value String to be checked
* @return true/false
*/
public static boolean isEmpty(String value) {
int strLen;
if (value == null || (strLen = value.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(value.charAt(i)) == false)) {
return false;
}
}
return true;
}
}