OpenAPI是优酷开放平台对外开放的后台接口的统称,基于标准http协议,可支持多平台。最新版本为OpenAPI v3.0,具有接入更快捷,更安全,访问速度更快等优点。
注:历史版本v2.0支持访问但不继续维护。
优酷开放平台通过API为开放者提供部分服务能力,同样遵循“先申请开通后使用”的原则,具体的申请开通流程请参见《开发者入门》和具体产品服务的说明文档。不同于API v2.0, API v3.0 接口采用 REST 风格,只需将所需参数拼装成http请求,即可调用,支持 http协议请求的程序语言(如php、java、asp等等),从而均可调用Youku开放平台API。调用原理示意图如下:
url | https://openapi.youku.com/router/rest.json |
功能描述 | 开发平台代理接口 |
返回格式 | Json,UTF8 |
HTTP请求方式 | POST、GET |
参数名 | 参数全称 | 必选 | 参数类型 | 参数描述 |
---|---|---|---|---|
opensysparams | open system params | true | String | 系统参数,参考1.1.3 opensysparams={"action":"youkucloud.cloudvod.videoinfo.get_videoinfo_byid", "timestamp":1448433,"client_id":"test","version":"3.0"} |
其它参数 | 对应业务接口的参数,参考业务接口 |
参数名 | 参数全称 | 必选 | 参数类型 | 参数描述 |
---|---|---|---|---|
action | action | true | String | API接口名称,详见 |
client_id | client_id | true | String | 应用的client id |
access_token | access token | false | String | oauth2的token |
timestamp | timestamp | true | String | 客户端当前时间戳,精确到秒,timestamp与开放平台请求时间误差为6分钟 |
version | version | true | String | API协议版本,默认值3.0 |
sign_method | sign_method | false | String | 签名的摘要算法,可选值为:HmacSHA256,md5。默认为md5 |
sign | sign | true | String | 对API调用参数(除sign外)的md5加密值。详情见签名方法 |
https://openapi.youku.com/router/rest.json?opensysparams= {“action”:“youkucloud.cloudvod.videoinfo.get_videoinfo_byid”, ”timestamp”:1448433,”version”:“1.0”, “sign”:“e401f24f95b91ad8fbe2655fbc771d31”, ”client_id”:“test”}&ids=10001
{ e:{ desc:"IP不可访问 [缺少ip]", provider: "openapiv3", code: -113 }, data: "", cost: 0.332000732421875 }
业务接口的结果原样返回。
错误码 | 错误描述 |
---|---|
-100 | 缺少必要参数,或者参数值格式不正确,请参考系统参数说明 |
-101 | 签名错误 |
-102 | timestamp与开放平台请求时间误差为6分钟 |
-103 | 拒绝访问,帐号被封禁,或者不在接口针对的用户范围内等 |
-105 | token验证失败 |
-106 | Server配置错误 |
-107 | app没有权限访问该分组 |
-108 | 接口不存在 |
-111 | oauth2服务异常 |
-113 | IP不可访问 |
-114 | clientid无效 |
-115 | clientid访问该组接口过于频繁 |
-117 | 应用级别不够 |
调用API 时需要对请求参数进行签名并传给开放平台,开放平台服务器会通过签名验证该请求的参数是否合法。签名方法如下:
(1)根据参数名称(除签名和图片)将所有请求参数按照字母先后顺序排序(系统参数为json格式,需要展开,如果系统参数与业务参数的key冲突,则系统参数在前面): key + value …. key + value 例如:将foo=1,bar=2,baz=3 排序为bar=2,baz=3,foo=1
(2)参数名和参数值连接再进行 URLEncode后,得到拼装字符串bar2baz3foo1
(3)如果是md5签名方式,将secret 拼接到参数字符串尾进行32位的小写md5加密后,格式是:md5(key1value1key2value2…secret)
(4)如果是HmacSHA256签名方式,则用secret对得到的拼装字符串bar2baz3foo1做签名,得到32位小写签名字符串
/** * @brief 签名 * @author luhanlin * @date 2016-05-12 * * @param params 需加密的参数,TreeMap保证参数按升序排序, * 非Java语言需要先按参数名进行排序,系统参数与业务参数相同的情况下,系统参数在前 * @param appKey 代理层获取密钥 * @param secret 加密密钥 * * @return 返回请求openapi所需参数, * 1、GET请求,直接遍历Map,拼接k-v即可; * 2、POST请求,迭代Map,封装为NameValuePair即可 */ public static TreeMapget_sign(TreeMap params, String appKey, String secret) throws Exception { /** * 用于存放与业务参数名相同的系统参数 */ Map serviceDuplicatePairs = new TreeMap<>(); if(params.get("client_id") != null) { serviceDuplicatePairs.put("client_id", appKey); } else { params.put("client_id", appKey); } if(params.get("timestamp") != null) { serviceDuplicatePairs.put("timestamp", System.currentTimeMillis() / 1000); } else { params.put("timestamp", System.currentTimeMillis() / 1000); } if(params.get("version") != null) { serviceDuplicatePairs.put("version", "3.0"); } else { params.put("version", "3.0"); } String signMethod = params.get("sign_method") == null ? null : params.get("sign_method").toString(); if(signMethod == null || "".equals(signMethod)) { signMethod = SignMethodEnum.MD5.getValue(); params.put("sign_method", signMethod); } else { serviceDuplicatePairs.put("sign_method", signMethod); } StringBuffer signString = new StringBuffer(); try { /** * 生成签名字符串 */ for(Map.Entry entry : params.entrySet()) { /** * 同名参数,系统参数置于业务参数前 */ if(serviceDuplicatePairs.get(entry.getKey()) != null) { signString.append(entry.getKey()); /** * 对参数值进行URLEncode, 不同开发语言对特殊字符encode结果可能不同, * 以Java URLEncoder结果为准 * Encode值可以参考http://tool.chinaz.com/tools/urlencode.aspx */ signString.append(URLEncoder.encode(serviceDuplicatePairs.get(entry.getKey()).toString(), "UTF-8")); } signString.append(entry.getKey()); signString.append(URLEncoder.encode(entry.getValue().toString(), "UTF-8")); } } catch (UnsupportedEncodingException e) { throw new Exception(ErrorCode.U8_ENCODE_ERROR.getDesc()); } // System.out.println(signString.toString()); String sign = ""; if(SignMethodEnum.isHmac(signMethod)){ try { sign = hmacSign(secret, signMethod, signString.toString()); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } } else { signString.append(secret); try { System.out.println(signString.toString()); sign = md5Sign(signString.toString()); } catch(Exception e) { params.put("error", ErrorCode.U8_ENCODE_ERROR.getCode()); return params; } } return packageRequestParams(params, serviceDuplicatePairs, appKey, sign); } /** * 拼接请求参数,返回Map方便post请求封装请求参数 * @param params 所有参数 * @param dupiicateParams 与业务参数名相同的系统参数 * @param appKey client_id * @param sign 加密字符串 * @return */ private static TreeMap packageRequestParams(TreeMap params, Map dupiicateParams, String appKey, String sign) { StringBuffer buffer = new StringBuffer(); /** * 拼接系统参数 */ buffer.append("{"); buffer.append("\"client_id\":"); buffer.append("\""); buffer.append(appKey); buffer.append("\","); buffer.append("\"timestamp\":"); buffer.append("\""); buffer.append(params.get("timestamp")); buffer.append("\","); buffer.append("\"version\":"); buffer.append("\"3.0\","); buffer.append("\"sign_method\":"); buffer.append("\""); buffer.append(params.get("sign_method")); buffer.append("\","); buffer.append("\"sign\":"); buffer.append("\""); buffer.append(sign); buffer.append("\","); buffer.append("\"action\":"); buffer.append("\""); buffer.append(params.get("action")); buffer.append("\""); String access_token = (String) params.get("access_token"); if(access_token != null && !"".equals(access_token)) { buffer.append(",\"access_token\":"); buffer.append("\""); buffer.append(access_token); buffer.append("\""); params.remove("access_token"); } buffer.append("}"); params.put("opensysparams", buffer.toString()); /** * 将Map中的系统参数移出 */ if(dupiicateParams.get("client_id") == null) { params.remove("client_id"); } if(dupiicateParams.get("timestamp") == null) { params.remove("timestamp"); } if(dupiicateParams.get("version") == null) { params.remove("version"); } if(dupiicateParams.get("sign_method") == null) { params.remove("sign_method"); } if(dupiicateParams.get("action") == null) { params.remove("action"); } return params; } private static String hmacSign(String secret, String signMethod, String signString) throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException { String algorithm = null; if(SignMethodEnum.HMAC.getValue().equals(signMethod)){ algorithm = SignMethodEnum.HMACMD5.getValue(); }else{ algorithm = signMethod; } SecretKey secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), algorithm); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); byte[] bytes = mac.doFinal(signString.getBytes("UTF-8")); System.out.println(signString.toString()); return byte2hex(bytes); } private static String md5Sign(String signString) { String sign = MD5.stringToMD5(signString); return sign; } 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.toLowerCase()); } return sign.toString(); }