API-V5 接口说明-通用接口标准
通用接口标准
传输协议标准
- “海量ADP大数据平台”提供在线的互联网服务,为开发者提供http/https接口,方便开发者与平台进行交互。
- 服务器提供http/https形式的访问接口,通过POST的方式,以JSON格式传递参数。
- 采用同步请求响应的模式提供返回数据。请求方将参数存放在规定的参数名中,发送给目标接口URL,接口的后端服务响应后会将结果返回给请求方。
数据格式标准
- 所有API接口统一采用 POST JSON 的请求方式
- 所有API接口返回内容统一采用 JSON 数据格式
- 文本编码统一为 utf-8
- 客户端请求
"Content-Type"需为"application/json" - 服务端返回
"Content-Type"均为"application/json"
访问接口标准
- 接口支持HTTP/HTTPS协议
- 接口仅支持POST方法进行调用
- 请求参数仅支持 JSON 格式的 BODY 内容
- 请求包含:公共参数 + 具体服务的特定参数
公共参数说明
- 公共参数的功能主要为身份认证,防止非法请求通过API访问系统功能
- 公共参数均在 HTTP HEADER 中,服务器通过 HEADER 中的信息进行身份认证
- 公共参数有如下几个:
| 参数名称 | 参数格式 | 参数描述 | 是否必需 | 备注 |
|---|---|---|---|---|
| hl_appkey | 字符串 | 用户appkey | 是 | 由海量提供的用户身份识别码,参与认证签名计算 |
| hl_time | 字符串 | 当前时间 | 是 | 当前北京时间,参与认证签名计算,格式为 “yyyy-mm-dd HH:MM:SS” |
| hl_sign | 字符串 | 认证签名 | 是 | 安全加密认证的参数, 请查看下面的具体说明 |
- 注意:上面参数均为系统保留字,请不要在其他参数中使用上述名称
- 以上三个参数每个接口都要使用,
hl_sign认证签名的生成方法,请参考后面章节 - [非必需]建议发送http请求访问接口时,Headers中设置
"Accept-Encoding:gzip"
关于认证签名的生成
- 每次调用 API 接口时,需要提供一个
hl_sign 认证签名参数,用于认证此次请求的合法性 - 海量会为每位客户提供一个 appkey 及与其对应的一组密钥(secret)
- 客户端发起请求前,需要利用这组密钥来生成
hl_sign的加密签名字符串,与请求一同提交给服务器
签名生成方法
- 客户端请求包括以下三部分:请求接口的 URL地址,公共参数(HEADER内),具体服务特定参数(JSON内)
- 海量API v5 接口统一使用的地址前缀为
https://api.hylanda.com/v5/ - 下面以
https://api.hylanda.com/v5/xuanzhi/media/publish_count接口(炫知媒体发稿量)为例,介绍生成步骤: 首先,假设您已经从海量获得了appkey及secret,如下
appkey : 123456789012345467890 secret : HZUQs7gLxQ1nFT0rKdSu0YuilGkkMF2T确定要调用的接口URL路径(完整URL去除域名),例如上述接口URL路径为
/v5/xuanzhi/media/publish_count- 将当前时间格式化为字符串(北京时间精确到秒),作为
hl_time参数的值 将接口的 公共参数 及 POST-JSON字符串 罗列出来(不含
hl_sign),即 hl_appkey、hl_time、json 三者,例如如下形式(还是以炫知媒体发稿量接口为例):hl_appkey : 123456789012345467890 hl_time : 2021-12-01 16:55:48 json : {"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}将 “参数名” 和 “参数值” 使用 “&” 和 “=” 做字符串拼接(注意:要保持上面的顺序),像这样:
hl_appkey=xxxxxxx&hl_time=xxxxxxxx&json=xxxxxxxxx
请注意:上述字符串拼接好后,不需要再进行其他处理,输出一个码制为UTF-8的字符串即可
重要:json部分有空格换行也不要紧,原样拼入上述字符串即可,但一旦拼好了,拼入字符串的这部分json,必须和最终POST的json一模一样,不能在POST时再追加或删减任何字符,包括空格、换行等
上例中,拼接后的字符串如下:
hl_appkey=123456789012345467890&hl_time=2021-12-01 16:55:48&json={"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}在字符串前面拼接上URL路径,并加上 “?” 符号连接,像这样:
/v5/xuanzhi/media/publish_count?hl_appkey=123456789012345467890&hl_time=2021-12-01 16:55:48&json={"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}在字符串尾部直接拼接上密钥(secret),像这样:
/v5/xuanzhi/media/publish_count?hl_appkey=123456789012345467890&hl_time=2021-12-01 16:55:48&json={"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}HZUQs7gLxQ1nFT0rKdSu0YuilGkkMF2T(这里假设 “HZUQs7gLxQ1nFT0rKdSu0YuilGkkMF2T” 是您的密钥)
将上述整个字符串计算 MD5 值,作为
hl_sign参数的值,加入请求参数中(若MD5函数需要unicode转码,像python之类,使用 UTF-8 转码即可)temp_string = '/v5/xuanzhi/media/publish_count?hl_appkey=123456789012345467890&hl_time=2021-12-01 16:55:48&json={"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}HZUQs7gLxQ1nFT0rKdSu0YuilGkkMF2T' hl_sign=md5(temp_string) ----计算MD5得出: hl_sign=f2b1add46f07dfe07a8231195f581f76 ----请注意:此`hl_sign`值有效期为`hl_time`开始的300秒内用POST JSON标准方式,输入公共参数和服务特定参数,发送给指定 API 接口即可:
POST https://api.hylanda.com/v5/xuanzhi/media/publish_count HEADERS: 'Content-Type: application/json' 'hl_appkey: 123456789012345467890' 'hl_time: 2021-12-01 16:55:48' 'hl_sign: f2b1add46f07dfe07a8231195f581f76' BODY: {"date": "2021-11-06", "name": "新华网", "type": "standard_media_name"}
请注意:无论任何情况下,请保护您的密钥(secret),不要在网络上明文传输,或发送给任何单位和个人,由此产生的损失将由泄密方承担。
通用返回信息
海量API接口的返回信息体的基本JSON结构如下
{
"res":0, //返回码,正常一般返回0,非零为各种异常情况,有时特殊接口会使用特殊返回值
"msg":"服务返回信息",
"特定服务其他返回字段":""
}
通用错误返回信息说明
| HTTP Code | HTTP Response Body | Description |
|---|---|---|
| 401 | { "res": 401, "msg": "data truncated (数据出错)" } |
传输的数据错误, 可能是通讯过程出现问题,尝试重试解决 |
| 401 | { "res": 401, "msg": "no JSON (未收到 POST JSON 数据)" } |
服务器没有收到接口参数数据, 请检查客户端参数 |
| 403 | { "res": 401, "msg": "validate clock failed (请求时间字段不存在或不合法)" } |
请检查hl_time参数,服务器仅响应 hl_time在最近300秒内的请求;也有可能是POST方式错误, 服务器没有接到 hl_time字段 |
| 403 | { "res": 403, "msg": "missing signature field (缺少认证所需签名字段)" } |
请检查hl_appkey,hl_time,hl_sign参数是否漏发,请补全后重试 |
| 403 | { "res": 403, "msg": "missing credential (未找到该用户的证书)" } |
请检查hl_appkey字段是否填错,系统没有找到对应用户的证书 |
| 403 | { "res": 403, "msg": "signature not same (签名校验失败)" } |
hl_sign签名校验失败,请检查 hl_sign的生成逻辑是否有误 |
| 200 | { "res": -1, "msg": "您没有调用此接口的权限" } |
授权信息无权访问此接口,请与相关人员确认您是否有权调用 |
调用接口的代码样例(python3)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created by chy on 2020/12/29 18:04
"""
本代码仅供向客户演示海量APIv5的调用方法
代码可以任意截取、复制到您的系统中
但本代码仅供演示调用方法,所用函数、库等并不一定是最优的,请使用此代码的开发人员根据自己系统的特点自行修改
"""
import datetime
import hashlib
import json
import requests
if __name__ == "__main__":
appkey = "这里填写你的appkey"
secret = "这里填写你的密钥"
# api_path 这里填写您要调用的api相对路径(不包含域名的部分) 这里只是个例子,请不要照搬
api_path = "/v5/xuanzhi/media/publish_count"
url = "https://api.hylanda.com"+api_path
headers = {
"Content-Type": "application/json",
"hl_appkey": appkey,
"hl_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
data = {
# 这里填写您要调用的API的参数,参数名和参数值都请参考对应的接口说明里写,这里只是一个例子,请不要照搬
"date": "2021-11-06",
"name": "新华网",
"type": "standard_media_name"
}
#将json对象dumps成为字符串
str_data_json = json.dumps(data, ensure_ascii=False)
#拼接用来计算md5的字符串
str_temp = f"{api_path}?hl_appkey={headers['hl_appkey']}&hl_time={headers['hl_time']}&json={str_data_json}" + secret
#计算md5
m = hashlib.md5()
m.update(str_temp.encode("utf8"))
#将算好的md5放进headers中
headers["hl_sign"] = m.hexdigest()
#开始请求接口
resp = requests.post(url, str_data_json.encode("utf-8"), headers=headers, timeout=30)
print(resp.status_code)
if resp is not None:
print( resp.json())
调用接口的代码样例(JAVA)
"""
本代码仅供向客户演示海量APIv5的调用方法
代码可以任意截取、复制到您的系统中
但本代码仅供演示调用方法,所用函数、库等并不一定是最优的,请使用此代码的开发人员根据自己系统的特点自行修改
"""
/**
* 计算sign值类
*/
import com.alibaba.fastjson.JSONObject;
import java.security.MessageDigest;
import java.util.Map;
import java.util.TreeMap;
public class ApiV5SignUtil {
public static String API_HOST = "https://api.hylanda.com";
public static String APPKEY = "这里填写你的appkey";
public static String SECRET = "这里填写你的密钥";
/**
* url为api除去域名的地址,如 /v5/xuanzhi/analysis/profile
*
*/
public static String getSign(String url, String hl_time, JSONObject param) {
String sign_str = url + "?hl_appkey=" + APPKEY + "&hl_time=" + hl_time + "&json=" + param + SECRET;
return MD5(sign_str).toLowerCase();
}
public final static String MD5(String s) {
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
try {
byte[] btInput = s.getBytes("UTF-8");
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest mdInst = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
mdInst.update(btInput);
// 获得密文
byte[] md = mdInst.digest();
// 把密文转换成十六进制的字符串形式
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
/**
* 请求样例类
*/
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* <dependency>
* <groupId>com.squareup.okhttp3</groupId>
* <artifactId>okhttp</artifactId>
* <version>4.9.0</version>
* </dependency>
*
*/
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
private static OkHttpClient getClient() {
return new OkHttpClient.Builder().readTimeout(60, TimeUnit.SECONDS).build();
}
public static String postJsonV5(String sub_url, JSONObject params) {
RequestBody body = RequestBody.create(params.toJSONString(), MediaType.get("application/json; charset=utf-8"));
String hl_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
String hl_sign = ApiV5SignUtil.getSign(sub_url, hl_time, params);
Request request = new Request.Builder()
.url(ApiV5SignUtil.API_HOST + sub_url)
.header("hl_appkey", ApiV5SignUtil.APPKEY)
.header("hl_time", hl_time)
.header("hl_sign", hl_sign)
.post(body)
.build();
try(Response response = getClient().newCall(request).execute()) {
if (response.code() == 200)
return response.body().string();
else
logger.error("--- http请求失败, code: " + response.code() + ", url: " + sub_url + ", params: " + params);
}
catch (IOException e){
logger.error("--- http请求异常: ", e);
}
return "";
}
}