前言:公司最近要实现一个视频播放的功能,正常是不需要移动端调用阿里云视频API的,这件事是由后台来完成的。但是既然需求交给我了,就要想办法完成。
先来看一眼官方的API调用文档
https://help.aliyun.com/document_detail/44435.html?spm=5176.product29932.6.618.DUYkdb
有人会说了你直接扔出个阿里云的API你这不是搞笑吗?少侠勿急,且听我细细道来。
调用流程
你要想GET请求网络,请求需要你一些参数,参数的第一位便是签名其余的便是一些公共参数,或者请求特定接口的一些参数。接下来我就要说一下签名的生成过程。
生成签名的过程
就以阿里云获取视频列表的接口为例
final String HTTP_METHOD = "GET";
final String SEPARATOR = "&";
final String EQUAL = "=";
private static final String ENCODE_TYPE = "UTF-8";
String Timestamp = formatIso8601Date(new Date());
String SignatureNonce = UUID.randomUUID().toString();
Map<String, String> parameterMapX = new HashMap<String, String>();
//=============7大公共参数==================================
parameterMapX.put("Format", "JSON");
parameterMapX.put("Version", "2017-03-21");
parameterMapX.put("SignatureMethod", "HMAC-SHA1");
parameterMapX.put("SignatureVersion", "1.0");
parameterMapX.put("AccessKeyId", WJ_Home_AccessKey);
parameterMapX.put("Timestamp", Timestamp);
parameterMapX.put("SignatureNonce", SignatureNonce);//随机数
//=============分割线下的是特有参数==================================
parameterMapX.put("Action", "GetVideoList");
parameterMapX.put("PageNo", "1");
parameterMapX.put("PageSize", "10");
parameterMapX.put("CateId", CateId);//视频分类id可以不用传,默认是-1
List<String> sortedKeys = new ArrayList<String>(parameterMapX.keySet());
Collections.sort(sortedKeys);
//开始生成签名
String PuR8IfTyWIan = GoToSign(sortedKeys, parameterMapX);
//拼接url请求网络了,我这里用的是nohttp的get请求 3.X
NetworkRequestX(PuR8IfTyWIan);
//计算ISO8601时间方法
private static String formatIso8601Date(Date date) {
SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df.format(date);
}
//转码工具类
private static String percentEncode(String value) {
if (value == null) return null;
try {
return URLEncoder.encode(value, ENCODE_TYPE).replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}
这里我把获取签名封装成了一个方法,更方便大家的使用
private String GoToSign(List<String> sortedKeys, Map<String, String> parameterMap) {
StringBuilder stringToSign = new StringBuilder();
stringToSign.append(HTTP_METHOD).append(SEPARATOR);
stringToSign.append(percentEncode("/")).append(SEPARATOR); //拼接的时候要进行转码
StringBuilder QueryString = new StringBuilder();
for (String key : sortedKeys) {
// 此处需要对key和value进行编码
String value = parameterMap.get(key);
QueryString.append(SEPARATOR).append(percentEncode(key)).
append(EQUAL).append(percentEncode(value));
}
//获取拼接的字符串 **拼接样式见1.X**
StringBuilder append = stringToSign.append(percentEncode(QueryString.toString().substring(1)));
//**hmac_sha1算法的第一个参数是密钥+&** 一定要加&
String PuR8IfTyWIan = hmac_sha1(AccessSecret+&, append.toString()).trim();
//通过Hmac_sha1算法计算出的 **拼接样式见2.X**
return PuR8IfTyWIan;
}
private String hmac_sha1(String key, String datas) {
String reString = "";
try {
byte[] data = key.getBytes("UTF-8");
//根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKey secretKey = new SecretKeySpec(data, "HmacSHA1");
//生成一个指定 Mac 算法 的 Mac 对象
Mac mac = Mac.getInstance("HmacSHA1");
//用给定密钥初始化 Mac 对象
mac.init(secretKey);
byte[] text = datas.getBytes("UTF-8");
//完成 Mac 操作
byte[] text1 = mac.doFinal(text);
reString = Base64.encodeToString(text1, Base64.DEFAULT);
} catch (Exception e) {
// TODO: handle exception
}
return reString;
}
拼接样式1.X
GET&%2F&AccessKeyId%3DLTAIPuR8IfTyWIan%26Action%3DGetVideoPlayAuth%26Format%3DJSON%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D578a50c1-280d-4a34-bffc-e0sda6b2df76%26SignatureVersion%3D1.0%26Timestamp%3D2017-08-11T08%253A56%253A39Z%26Version%3D2017-03-21%26VideoId%3D86d0a02dfccc46bab045d954e6b70036
拼接样式2.X
9or7epLWdsgMIvtRlJZm57HpBGs=
样式3.X
最后我强调一点 就是拼接URL这一点(我在拼接的时候没有进行转码,也能请求成功!)
我的URL
http://vod.cn-shanghai.aliyuncs.com?Signature=7K0h2pa/JS4KdC6XEKiYrw7a3EU=&SignatureNonce=bb8d6d93-e56c-4e76-b7d8-f4be3490b7e6&Format=JSON&CateId=133999353&SignatureMethod=HMAC-SHA1&Timestamp=2017-08-13T13%3A15%3A22Z&SignatureVersion=1.0&Action=GetVideoList&Version=2017-03-21&PageNo=1&PageSize=10&AccessKeyId=LTAIPuR8IfTyWIan
阿里云的URL
http://vod.cn-shanghai.aliyuncs.com?Signature=UI%2FwKfuvTtphzCKHwPhP0ErtLnc%3D&SignatureVersion=1.0&Action=GetVideoPlayAuth&Format=JSON&VideoId=68a4d2629a339db3207963ac073a88cd&SignatureNonce=578a50c1-280d-4a34-bffc-e06aa6b2df76&Version=2017-03-21&AccessKeyId=testId&SignatureMethod=HMAC-SHA1&Timestamp=2017-03-29T12%3A09%3A11Z
有人就会说了为什么你不跟着阿里爸爸方法走呢?
经过hmac_sha1我的转码后的签名,
UI%2QcKDaeGtplzCJHwPhP0ErtLnc%3DOA
阿里云的转码后的签名
UI%2FwKfuvTtphzCKHwPhP0ErtLnc%3D
为什么没有跟阿里爸爸的方法走,是因为我转码过后就多出个0A,如果按照阿里云的调用方式最后等待我的结果只有SignatureDoesNotMatch
API给的方法是这样的
// 生成请求URL
StringBuilder requestURL;
requestURL = new StringBuilder("http://vod.cn-shanghai.aliyuncs.com?");
requestURL.append(URLEncoder.encode("Signature", ENCODE_TYPE)).append("=").append(signature);
for (Map.Entry<String, String> e : parameterMap.entrySet()) {
requestURL.append("&").append(percentEncode(e.getKey())).append("=").append(percentEncode(e.getValue()));
因为它把集合中的数据进行了转码,当生成了URL,你对这个url进行请求的时候InvalidTimeStamp.Format时间戳格式不对
解决办法
requestURL.append("&").append(e.getKey()).append("=").append(e.getValue());
希望这篇博客可以帮助到你