#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2014 Yottabyte
import time
import hashlib
import urllib2
import urllib
_access_key = "26d79d9f3e5033d4be8ad5c41355e9be"
_secure_key = "10d052f85b421cf4a45ecf287183233d"
# @brief: API签名计算
# @param: origin_params 是用户原始的请求hash
# @param: secure_key是分发给用户的secure_key
# @param: query_time是签名的时间,为以毫秒计的Unix时间戳
# @returns: 长度为32的API签名结果
def _compute_sign(origin_params, secure_key, query_time):
sign_arr = []
# 使用签名时间,sk和用户原始请求来生成签名,保证唯一性。
# 注意三个字符串拼接先后顺序是签名时间,原始请求,私钥
sign_arr.append(str(query_time))
sign_arr.append(_sorted_query_str(origin_params))
sign_arr.append(secure_key)
return _md5("".join(sign_arr))
# @brief: 通过md5摘要生成算法计算签名
# @param: i_str是待计算的字符串
# @returns: md5的结果截取前32位
def _md5(i_str):
h = hashlib.md5()
h.update(i_str)
return h.hexdigest()[0:32]
# @brief: 将用户的原始请求按照key排序后拼接为一个字符串
# @param: query_hash 用户原始的请求参数,可以为空{}
# @returns: 原始请求对应的唯一字符串
def _sorted_query_str(query_hash):
return "&".join([ k+"="+query_hash[k] for k in sorted(query_hash.keys()) ])
if __name__ == '__main__':
#用户的原始请求URI部分
origin_params = {'query': '*'}
#统计请求JSON
post_body = '{ "query": { "status_split_numberic_histogram_result": { "histogram": { "field": "apache.status", "interval": 100 } }, "method_split_result": { "terms": { "field": "apache.method" }, "group": { "resp_len_stats_result": { "stats": { "field": "apache.resp_len" } } } } } }'
#用户请求签名的时间
qtime = int(time.time() * 1000)
#计算用户签名
sign = _compute_sign(origin_params, _secure_key, qtime)
# 为了验签所有API请求都需要额外增加的参数
additional_params = {
'qt': qtime,
'sign' : sign,
'ak': _access_key,
}
# 将用户原始参数和额外参数合并
req_params = dict(origin_params.items() + additional_params.items())
# 拼接query
req_url = 'http://yottaapi-test:8190/v0/statistic?' + urllib.urlencode(req_params)
# 发起请求,获取结果
print(urllib2.urlopen(req_url, data=post_body).read())
java样例:
// Copyright 2014 Yottabyte
package cn.yottabyte.api.stats;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
public class Main {
public static String accessKey = "4b40905b8eeee0cab799154c2baef788";
public static String secureKey = "2535c004c17f7565d18ca0bc51df65ac";
// @brief: API签名计算
// @param: originParams 是用户原始的请求hash
// @param: secureKey是分发给用户的secure_key
// @param: queryTime是签名的时间,为以毫秒计的Unix时间戳
// @return: 长度为32的API签名结果
public static String computeSign(HashMap<String, String> originParams,
String secureKey,
Long queryTime) {
// 使用签名时间,sk和用户原始请求来生成签名,保证唯一性。
// 注意三个字符串拼接先后顺序是签名时间,原始请求,私钥
ArrayList<String> list = new ArrayList<String>();
list.add(queryTime.toString());
list.add(sortedQueryStr(originParams));
list.add(secureKey);
return md5(StringUtils.join(list.toArray(new String[0]), ""));
}
// @brief: 通过md5摘要生成算法计算签名
// @param: sourceStr是待计算的字符串
// @returns: md5的结果截取前32位
public static String md5(String sourceStr) {
String result;
try {
byte[] bytesOfMessage = sourceStr.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < thedigest.length; offset++) {
i = thedigest[offset];
if (i < 0)
i += 256;
if (i < 16)
buf.append("0");
buf.append(Integer.toHexString(i));
}
result = buf.toString();
} catch (Exception e) {
System.err.println("Exception in md5.");
result = "";
}
return result;
}
// @brief: 将用户的原始请求按照key排序后拼接为一个字符串
// @param: queryHash 用户原始的请求参数,可以为空{}
// @returns: 原始请求对应的唯一字符串
public static String sortedQueryStr(HashMap<String, String> queryHash) {
String[] keys = queryHash.keySet().toArray(new String[0]);
Arrays.sort(keys);
ArrayList<String> params = new ArrayList<String>();
for (int i = 0; i < keys.length; i++) {
String k = keys[i];
String v = queryHash.get(k);
params.add(k + "=" + v);
}
return StringUtils.join(params.toArray(new String[0]), "&");
}
public static void main(String[] args) {
HashMap<String, String> originParams = new HashMap<String, String>();
// 用户的原始请求
originParams.put("query", "*");
originParams.put("time_range", "-1h,now");
// 用户请求签名的时间
Long queryTime = new Long(new Date().getTime());
// 计算用户签名
String sign = computeSign(originParams, secureKey, queryTime);
// 为了验签所有API请求都需要额外增加的参数
HashMap<String, String> additionalParams = new HashMap<String, String>();
additionalParams.put("qt", queryTime.toString());
additionalParams.put("sign", sign);
additionalParams.put("ak", accessKey);
// 拼接query
URIBuilder uriBuilder = new URIBuilder();
uriBuilder.setScheme("http");
uriBuilder.setHost("yottaapi.test");
uriBuilder.setPort(8190);
uriBuilder.setPath("/v0/statistic/");
String[] originKeys = originParams.keySet().toArray(new String[0]);
for (int i = 0; i < originKeys.length; i++) {
uriBuilder.addParameter(originKeys[i], originParams.get(originKeys[i]));
}
String[] additionalKeys = additionalParams.keySet().toArray(new String[0]);
for (int i = 0; i < additionalKeys.length; i++) {
uriBuilder.addParameter(additionalKeys[i], additionalParams.get(additionalKeys[i]));
}
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
// 打印GET方法的uri
String uri = uriBuilder.build().toString();
System.out.println(uri);
// 发起请求
HttpPost httpPost = new HttpPost(uri);
StringEntity stringEntity = new StringEntity(
"{ \"query\": { "
+ " \"status_split_numberic_histogram_result\": { "
+ "\"histogram\": { "
+ "\"field\": \"apache.status\","
+ "\"interval\": 100 "
+ "} "
+ "},"
+ " \"method_split_result\": { "
+ "\"terms\": { "
+ " \"field\": \"apache.method\" "
+ "}, "
+ "\"group\": { "
+ " \"resp_len_stats_result\": { "
+ "\"stats\": { "
+ "\"field\": \"apache.resp_len\" "
+"} "
+ "} "
+"} "
+"} "
+ " } }");
httpPost.setEntity(stringEntity);
CloseableHttpResponse response = httpclient.execute(httpPost);
try {
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
// 获得结果
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
} catch(Exception e) {
System.err.println("Handle result exception!" + e.toString());
} finally {
response.close();
}
} catch(Exception e) {
System.err.println("Request Exception!" + e.toString());
} finally {
try {
httpclient.close();
} catch(Exception e) {
System.out.println("Close client Exception!" + e.toString());
}
}
}
}