如何调用API
构造请求
API 的请求方式仅支持POST
请求URL由如下部分构成:{URI-scheme} :// {address} / {path}
- URI-scheme:表示用于传输请求的协议,当前所有API均采用HTTPS协议。
- address:指定承载REST服务端点的服务器域名或IP。
- path:资源路径,也即API访问路径。从具体API的URI模块获取,例如“查询设备详情”API的path为"openApi/v2/node/query"。
请求签名
调用接口时必须携带请求签名,平台会对根据签名值对调用方进行身份核验
调用方使用约定的签名计算方法计算出本次请求的签名值,
计算签名sign
计算sign值,是发起调用请求的第一步。post请求的content-type当前支持两种方式application/json和multipart/form-data,下面将分开展示两种方式下的sign计算方式。
什么是sign
sign是使用MD5算法(32位小写),通过对appId、appSecret、随机数和请求参数,通过md5算法进行摘要,得到的一个字符串,具体签名算法见<签名示例>。为了安全考虑,客户端每次请求, 都需要根据随机数生成新的sign,同一个sign只能使用一次。
计算方法如下:
sign = MD5(appId+appSecret+bodyString+nonce)
其中bodyString为POST请求body的String格式,需要将body参数按照参数名称的字典顺序升序排序后转换。
sign计算示例
java 计算签名示例1 (content-type:application/json)
@Test
public void testJson(){
RestTemplate restTemplate = new RestTemplate();
// 随机数
Long nonce = System.currentTimeMillis();
// 创建api应用生成的appId
String appId = "Your appId";
// 创建api应用生成的appSecret
String appSecret = "Your appSecret";
// 鉴权令牌
String token = "Your token";
// 请求参数
Map<String, Object> bodyMap = new HashMap<>();
bodyMap.put("name", "xiot");
bodyMap.put("value", "1000");
bodyMap.put("key", 20);
// 根据参数名称排序
TreeMap<String, Object> treeMap = new TreeMap<String, Object>(bodyMap);
// 请求体 body
JSONObject body = new JSONObject(bodyMap);
String bodyString = JSONObject.toJSONString(treeMap);
// 请求头header
MultiValueMap<String, String> header = new HttpHeaders();
header.add("appId", appId);
header.add("nonce", nonce.toString());
header.add("sign", getSign(appId, appSecret, nonce.toString(), bodyString));
header.add("authorization", token);
HttpEntity<Object> entry = new HttpEntity<>(body, header);
// 发起请求
ResponseEntity<String> response = restTemplate.postForEntity("https://address(地址)/path(api)", entry, String.class);
// 打印返回参数
System.out.println(response.getBody());
}
/**
* @ desc : 计算签名,采用MD5摘要方式 不加盐,不迭代
* @ params [appId(应用Id), appSecret(密钥), nonce(随机数), bodyString(请求body的json字符串)]
* @ return
*/
private String getSign(String appId, String appSecret, String nonce, String bodyString) {
StringBuilder dataString = new StringBuilder()
.append(appId)
.append(appSecret)
.append(bodyString)
.append(nonce);
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] md5 = digest.digest(dataString.toString().getBytes());
return Hex.encodeHexString(md5);
}
java 计算签名示例 2 (content-type:multipart/form-data)
特别注意: 请求时应当设置如下参数
header.setContentType(MediaType.MULTIPART_FORM_DATA);
requestBody.add("file", file.getResource());
form-data的参数格式用于上传文件,如固件添加接口。计算签名示例如下
// 1 formdata 参数中除了file 文件参数外,其他参数拼接成字符串,如下
请求参数:
name:api测试上传
hardVer:V2.0.0
productId:EF1D793B
remark:api上传固件3a
softVer:V1.1.1
排序并拼接后得到拼接新的字符串
bodyString = "hardVer:V2.0.0,name:api测试上传,productId:EF1D793B,remark:api上传固件3a,softVer:V1.1.1"
// 2 对上述字符串计算sign值,调用上个示例中getSign函数,即appId+appSecret+bodyString+nonce(随机数) 得到拼接新的字符串后md5加密,得到sign
// 3 Header上添加计算完成的sign、nonce、appId、authorization后发起formdata请求即可,
返回结果
状态码
请求发送以后,您会收到响应,包含状态码、响应消息头和消息体。 状态码是一组数字代码,状态码表示了请求响应的状态,完整的状态码列表请参见状态码。
对于当前版本接口,如果调用后返回状态码为"8001",则表示请求成功,其余则为失败。
响应消息头
对应请求消息头,响应同样也有消息头,如“Content-type”等。
响应消息体
响应消息体通常以结构化格式返回,与响应消息头中Content-type对应,传递除响应消息头之外的内容。 响应示例
{
"code": "8001",
"msg": "操作成功",
"data": {
"records": [
{
"productId": "AA30C505",
"productName": "MQTT20协议JSON测试",
"nodeEui": "20MQTT000507",
"module": "default",
"moduleName": "默认",
"otaType": 2,
"softVer": "v1.3",
"hardVer": "v1.5",
"reportAt": "2023-02-06 17:26:50"
}
],
"current": 1,
"size": 10,
"total": 1
}
}
当接口调用出错时,会返回错误码及错误信息说明,错误响应的Body体格式如下所示。
{
"code": "67002",
"msg": "产品已存在推送应用",
"data": "产品id(xxxxx)已存在推送应用"
}