开放平台(TOP)的API是基于HTTP协议来调用的,开发者(ISV)可以直接使用TOP提供的官方SDK(支持多种语言,包含了请求的封装,签名加密,响应解释,性能优化等)来调用,也可以根据TOP的协议来封装HTTP请求进行调用,以下主要是针对自行封装HTTP请求进行API调用的原理进行详细解说。
调用API的服务URL地址,开放平台目前提供了2个环境给ISV使用:正式环境,海外环境。
① 正式环境: ISV软件创建应用后调用接口使用请求地址 ,请使用https方式。
② 海外环境: 海外环境主要是给海外(欧美国家)ISV使用,对于海外的ISV,使用海外环境会比国内环境的性能高一倍。
调用环境 | 服务地址 |
正式环境 | https://gw.api.taobao.com/router/rest |
海外环境 | https://api.taobao.com/router/rest |
调用任何一个API都必须传入的参数,目前支持的公共参数有:
参数名称 |
参数类型 |
是否必须 |
参数描述 |
method |
String |
是 |
具体API接口名称,例:taobao.item.seller.get |
app_key |
String |
是 |
TOP分配给应用的AppKey。例:12345678 |
session |
String |
可选 |
用户授权成功后,平台颁发给应用的授权session,详细介绍请点击这里。当此API文档的标签上注明:“需要授权”,则此参数必传;“不需要授权”,则此参数不需要传。 |
timestamp |
String |
是 |
时间戳,格式为yyyy-MM-dd HH:mm:ss,时区为GMT+8,例如:2016-01-01 12:00:00。淘宝API服务端允许客户端请求最大时间误差为10分钟。 |
v |
String |
是 |
API协议版本,可选值:2.0 |
sign_method |
String |
是 |
签名的摘要算法,可选值为:hmac,md5,hmac-sha256。 |
sign |
String |
是 |
API输入参数签名结果,签名算法参照下面的介绍。 |
format |
String |
否 |
返回内容响应格式。不传默认为xml格式,可选值:xml,json。 |
simplify |
Boolean |
否 |
是否采用精简JSON返回格式,仅当format=json时有效,可选值:false,true,不传为false。 |
API调用除了必须包含公共参数外,如果API本身有业务级的参数也必须传入,每个API的业务级参数请考API文档说明。
为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,TOP服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。TOP目前支持的签名算法有三种:MD5(sign_method=md5),HMAC_MD5(sign_method=hmac),HMAC_SHA256(sign_method=hmac-sha256),签名大体过程如下:
1)对所有API请求参数(包括公共参数和业务参数,但除去sign参数和byte[]类型的参数),根据参数名称的ASCII码表的顺序排序。如:foo:1, bar:2, foo_bar:3, foobar:4排序后的顺序是bar:2, foo:1, foo_bar:3, foobar:4。
2)将排序好的参数名和参数值拼装在一起,根据上面的示例得到的结果为:bar2foo1foo_bar3foobar4。
3)把拼装好的字符串采用utf-8编码,使用签名算法对编码后的字节流进行摘要。如果使用MD5算法,则需要在拼装的字符串前后加上app的secret后,再进行摘要,如:md5(secret+bar2foo1foo_bar3foobar4+secret);如果使用HMAC_MD5算法,则需要用app的secret初始化摘要算法后,再进行摘要,如:hmac_md5(bar2foo1foo_bar3foobar4)。
4)将摘要得到的字节流结果使用十六进制表示,如:hex("helloworld".getBytes("utf-8")) = "68656C6C6F776F726C64"
说明:MD5和HMAC_MD5都是128位长度的摘要算法,用16进制表示,一个十六进制的字符能表示4个位,所以签名后的字符串长度固定为32个十六进制字符。
JAVA签名示例代码
public static String signTopRequest(Map<String, String> params, String secret, String signMethod) throws IOException { // 第一步:检查参数是否已经排序 String[] keys = params.keySet().toArray(new String[0]); Arrays.sort(keys); // 第二步:把所有参数名和参数值串在一起 StringBuilder query = new StringBuilder(); if (Constants.SIGN_METHOD_MD5.equals(signMethod)) { //签名的摘要算法,可选值为:hmac,md5,hmac-sha256 query.append(secret); } for (String key : keys) { String value = params.get(key); if (StringUtils.areNotEmpty(key, value)) { query.append(key).append(value); } } // 第三步:使用MD5/HMAC加密 byte[] bytes; if (Constants.SIGN_METHOD_HMAC.equals(signMethod)) { bytes = encryptHMAC(query.toString(), secret); } else { query.append(secret); bytes = encryptMD5(query.toString()); } // 第四步:把二进制转化为大写的十六进制(正确签名应该为32大写字符串,此方法需要时使用) //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 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; }
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(); }
C#签名示例代码
public static string SignTopRequest(IDictionary<string, string> parameters, string secret, string signMethod) { // 第一步:把字典按Key的字母顺序排序 IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal); IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); // 第二步:把所有参数名和参数值串在一起 StringBuilder query = new StringBuilder(); if (Constants.SIGN_METHOD_MD5.Equals(signMethod)) //签名的摘要算法,可选值为:hmac,md5,hmac-sha256 { 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); } } // 第三步:使用MD5/HMAC加密 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())); } // 第四步:把二进制转化为大写的十六进制 StringBuilder result = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { result.Append(bytes[i].ToString("X2")); } return result.ToString(); }
其他语言签名示例代码请参见TOP官方SDK源代码。
以taobao.item.seller.get调用为例,具体步骤如下:
参数类型 |
参数设置值 |
公共参数 |
method=taobao.item.seller.get app_key=12345678 session=test timestamp=2016-01-01 12:00:00 format=json v=2.0 sign_method=md5 |
业务参数 |
fields=num_iid,title,nick,price,num num_iid=11223344 |
app_key12345678fieldsnum_iid,title,nick,price,numformatjsonmethodtaobao.item.seller.getnum_iid11223344sessiontestsign_methodmd5timestamp2016-01-01 12:00:00v2.0
假设app的secret为helloworld,则签名结果为:hex(md5(helloworld+按顺序拼接好的参数名与参数值+helloworld)) = "66987CB115214E59E6EC978214934FB8"。
将所有参数名和参数值采用utf-8进行URL编码(参数顺序可随意,但必须要包括签名参数),然后通过GET或POST(含byte[]类型参数)发起请求,如:
https://gw.api.taobao.com/router/rest?method=taobao.item.seller.get&app_key=12345678&session=test×tamp=2016-01-01+12%3A00%3A00&format=json&v=2.0&sign_method=md5&fields=num_iid%2Ctitle%2Cnick%2Cprice%2Cnum&num_iid=11223344&sign=66987CB115214E59E6EC978214934FB8
1. 所有的请求和响应数据编码皆为utf-8格式,URL里的所有参数名和参数值请做URL编码。如果请求的Content-Type是application/x-www-form-urlencoded,则HTTP Body体里的所有参数值也做URL编码;如果是multipart/form-data格式,每个表单字段的参数值无需编码,但每个表单字段的charset部分需要指定为utf-8。
2. 参数名与参数值拼装起来的URL长度小于1024个字符时,可以用GET发起请求;参数类型含byte[]类型或拼装好的请求URL过长时,必须用POST发起请求。所有API都可以用POST发起请求,但要求系统参数都放在query体中,比如上述HTTP请求,系统参数app_key应该在queryt体,而业务参数fields可以在body体里,也可以在在query体,但推荐放body体,防止URL过长。
3. 生成签名(sign)仅对未使用TOP官方SDK进行API调用时需要操作,如使用了TOP官方SDK,该步骤SDK会自动完成。
错误码 | 错误信息 | 错误原因 | 解决方案 |
7 | msg:App Call Limited sub_code:accesscontrol.limited-by-app-access-count |
该应用(appkey)调用流量达到当天限制 | 1)现在提供了紧急流量重置功能,每天可以刷新三次,流量重置后会清零重新统计。 步骤:登录 开放平台控制台--应用管理--选择对应应用管理--APP证书-- 点击 重置流量控制 ,就可以触发流量刷新。 2)后续可在 支持中心提交工单,让技术支持小二申请更高流量。 |
7 | msg:App Call Limited sub_code:accesscontrol.limited-by-api-access-count |
对单接口(api)调用总频率的达到限制 | 1)该限制是平台针对所有isv应用同时访问某个api接口每分钟或每秒钟调用总量的限制。是api级别的限制,与单个isv应用(appkey)无关,api级别流量限制目的是防止短时间内请求量过大影响后端服务的稳定性。 2)api限流报错,一般无法进行调整,只能稍后重试。此种错误一般还伴有“This ban will last for ** more seconds” 的信息,意思是等待**秒钟以后再调用。
解决办法: 建议ISV调整降低该接口调用频率,错开高峰期调用。或者使用其他可接口进行分流。 |
7 | msg:App Call Limited sub_code:accesscontrol.limited-by-app-api-access-count |
平台限制单appkey调用某个接口的频率 | 接口业务方为了帮助每个appkey接口调用资源的合理分配,做的每个应用的频率限制,依照“This ban will last for ** more seconds” 中提示的限制时间结束后再调用。 |
11 | Insufficient ISV Permissions |
开发者权限不足 | 1)isv.permission-api-package-empty 没有和任何访问包关联,建议根据业务规则申请对应的权限; 2)isv.permission-api-package-not-allowed 不允许访问不可访问组的API,建议检查一下自己申请的应用标签是否正确,如果确实需要访问不可访问组的API需要根据业务规则到对应的业务线申请权限 例如:买家不可访问组就会有一些订单API不允许买家应用访问; 3)isv.permission-api-package-limit 关联的包中不允许访问该API,建议根据业务规则申请对应的权限; 4)isv.permission-ip-whitelist-limit IP限制不允许访问,建议到安全中心配置正确的IP白名单。 |
21 | Missing Method | 缺少方法名参数 | 传入的参数加入method字段。 |
22 | Invalid Method | 不存在的方法名 | 传入的method字段必需是你所调用的API的名称,并且该API是确实存在的。 |
24 | Missing Signature | 缺少签名参数 | 传入的参数中必需包含sign字段。 |
25 | Invalid Signature | 无效签名 | 1)检查appsecret是否正确,一般都是由于appsecret不对导致。 2)再签名算法是否正确,必需根据正确的算法算出来的。 |
26 | Missing Session | 缺少SessionKey参数 | 传入的参数中必需包含session字段。 |
27 | Invalid Session | 无效的SessionKey参数 | 如果报session不合法可能是用户没有绑定session或session过期造成的,用户需要重新授权一下然后传入新的sessionKey; 另外检查生成的sessionkey和appkey是否匹配。 |
28 | Missing App Key | 缺少AppKey参数 | 传入的参数必需包含app_key字段。 |
29 | Invalid App Key | 无效的AppKey参数 | appkey传入不对,确保appkey可用或者请求API的环境一致。 |