## 通信协议
HTTPS 协议。

## 请求方法
网易易盾提供的所有接口，均支持 POST/GET 方法。当参数名与参数值拼装起来的 URL 长度小于 1024 个字符时，可以用GET发起请求；当参数类型含 byte[] 类型或拼装好的请求URL过长时，必须用 POST 发起请求。建议所有API调用都使用 POST 方法请求。

当前仅支持post请求的Content-Type: application/x-www-form-urlencoded格式，不支持application/json。

## 字符编码
所有接口的请求和响应数据编码皆为 utf-8。

## API请求结构
| 名称     | 描述                     | 备注                                           |
| -------- | ------------------------ | ---------------------------------------------- |
| API入口  | 具体API接口地址          | 如 `https://verify.dun.163yun.com/vx/xx/check` |
| 公共参数 | 每个接口都包含的通用参数 | 详见 [公共参数](http://support.dun.163.com/documents/391676076156063744?docId=411012634773868544&locale=zh-cn#请求公共参数) 说明                      |
| 私有参数 | 每个接口特有的参数       | 详见每个API接口定义                            |

# 公共参数
公共参数是用于标识产品和接口鉴权目的的参数，如非必要，在每个接口单独的接口文档中不再对这些参数进行说明，每次请求均需要携带这些参数。

## 请求公共参数

| 参数名称   | 类型   | 是否必选 | 最大长度 | 描述                                                         |
| ---------- | ------ | -------- | -------- | ------------------------------------------------------------ |
| secretId   | String | Y        | 32       | 产品秘钥 id ，在网易易盾创建产品时统一分配，产品标识         |
| businessId | String | Y        | 32       | 业务id ，在网易易盾创建产品时统一分配，业务标识              |
| version    | String | Y        | 4        | 接口版本号，可选值 v1                                        |
| timestamp  | Number | Y        | 13       | 请求当前 UNIX 时间戳（毫秒单位），请注意服务器时间是否同步               |
| nonce      | Number | Y        | 11       | 随机正整数，与 timestamp 联合起来，用于防止重放攻击          |
| signature       | String | Y        | 32       | 请求签名，用来验证此次请求的合法性，具体算法见 [接口鉴权](http://support.dun.163.com/documents/391676076156063744?docId=411012634773868544&locale=zh-cn#申请安全凭证) |
| signatureMethod | String | N        | 32       | 签名算法，可选值为MD5、SHA1、SHA256、SM3。如果不传该字段，默认采用MD5算法生成签名。 |

## 响应通用字段
所有接口响应值采用 json 格式， 如无特殊说明，每次请求的返回值中，都包含下面字段：

| 参数名称 | 类型   | 描述                                                         |
| -------- | ------ | ------------------------------------------------------------ |
| code     | Number | 接口调用状态，200:正常，其他值：调用出错，返回码见 [响应返回码](http://support.dun.163.com/documents/391676076156063744?docId=411012634773868544&locale=zh-cn#响应返回码) |
| msg      | String | 结果说明，如果接口调用出错，那么返回错误描述，成功返回 ok    |
| result   | String | 接口返回结果，各个接口自定义                                 |


## 响应返回码

响应返回码（code）反应了网易易盾服务 API 调用和执行的概要结果。当返回码不为 200 时， 表示请求未正常执行，返回码描述 (msg) 对该结果进行了细化补充，用户可根据返回码判断 API 的执行情况。

所有接口调用返回值均包含 code 和 msg 字段， code 为返回码值，msg 为返回码描述信息，返回码表如下：

| 返回码 | 返回码描述                 | 说明                                 |
| ------ | -------------------------- | ------------------------------------ |
| 200    | ok                         | 接口调用成功                         |
| 400    | bad request                | 请求缺少 secretId 或 businessId      |
| 401    | forbidden                  | secretId 或 businessId 错误          |
| 402    | business offline           | 业务未上线                           |
| 405    | param error                | 请求参数异常                         |
| 410    | signature failure          | 签名验证失败，请重新参考demo签名代码 |
| 411    | high frequency             | 请求频率或数量超过限制               |
| 420    | request expired            | 请求过期                             |
| 430    | replay attack              | 重放攻击                             |
| 503    | service unavailable        | 接口异常                             |
| 504    | exceed business call limit | 次数超限                             |
| 505    | service expire             | 服务未开通或已过期                   |
| 508    | trailcount not enough             | 试用条数不足                   |

# 接口鉴权

网易易盾的所有服务使用签名方法对接口进行鉴权，所有接口每一次请求都需要包含签名信息（signature 参数），以验证用户身份，防止信息被恶意篡改。

## 申请安全凭证

在第一次使用 API 之前，需申请安全凭证，安全凭证包括 SecretId 和 SecretKey ，SecretId 是用于标识 API 调用者的身份，SecretKey 是用于加密签名字符串和服务器端验证签名字符串的密钥。SecretKey 必须严格保管，避免泄露。

## 签名生成算法

签名生成方法如下：

- 对所有请求参数（包括公有参数和私有参数，但不包括 signature 参数），按照参数名ASCII码表升序顺序排序。如：foo=1， bar=2， foobar=3， baz=4 排序后的顺序是 bar=2， baz=4， foo=1， foobar=3。
- 将排序好的参数名和参数值构造成字符串，格式为：key1+value1+key2+value2… 。根据上面的示例得到的构造结果为：bar2baz4foo1foobar3 。
- 选择与 secretId 配对的 secretKey ，加到上一步构造好的参数字符串之后，如 secretKey=6308afb129ea00301bd7c79621d07591 ，则最后的参数字符串为 bar2baz4foo1foobar36308afb129ea00301bd7c79621d07591。
- 把上一步骤拼装好的字符串采用 utf-8 编码，使用提供的签名算法对字符串进行摘要，计算得到 signature 参数值，将其加入到接口请求参数中即可。

签名生成示例代码：

```java
/**
* 生成签名信息
* @param secretKey 产品私钥
* @param params 接口请求参数名和参数值map，不包括signature参数名
* @return
* @throws UnsupportedEncodingException
*/
public static String getSignature(String secretKey, Map<String, String> params) throws UnsupportedEncodingException {
    return getSignature(secretKey, params, params.get("signatureMethod"));
}
/**
* 生成签名信息
* @param secretKey 产品私钥
* @param params 接口请求参数名和参数值map，不包括signature参数名
* @param signatureMethod 加密方法
* @return
* @throws UnsupportedEncodingException
*/
public static String genSignature(String secretKey, Map<String, String> params, String signatureMethod) throws UnsupportedEncodingException {
    // 1. 参数名按照ASCII码表升序排序
    String[] keys = params.keySet().toArray(new String[0]);
    Arrays.sort(keys);

    // 2. 按照排序拼接参数名与参数值
    StringBuffer paramBuffer = new StringBuffer();
    for (String key : keys) {
        paramBuffer.append(key).append(params.get(key) == null ? "" : params.get(key));
    }
    // 3. 将secretKey拼接到最后
    paramBuffer.append(secretKey);

    if (StringUtils.isEmpty(signatureMethod)) {
        // 4. MD5是128位长度的摘要算法，用16进制表示，一个十六进制的字符能表示4个位，所以签名后的字符串长度固定为32个十六进制字符。
        return DigestUtils.md5Hex(paramBuffer.toString().getBytes("UTF-8"));
    } else {
        switch (SignatureMethodEnum.valueOf(StringUtils.upperCase(signatureMethod))) {
              case MD5:
                  return DigestUtils.md5Hex(paramBuffer.toString().getBytes("UTF-8"));
              case SHA1:
                  return DigestUtils.sha1Hex(paramBuffer.toString().getBytes("UTF-8"));
              case SHA256:
                  return DigestUtils.sha256Hex(paramBuffer.toString().getBytes("UTF-8"));
              case SM3:
                  return sm3DigestHex(paramBuffer.toString().getBytes("UTF-8"));
              default:
                  return "";
         }
    }
    return "";
}
```

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""生成签名信息
Args:
    secretKey 产品私钥
    params 接口请求参数，不包括signature参数
"""
def gen_signature(secretKey, params=None):
        params_str = ""
        for k in sorted(params.keys()):
            params_str += str(k)+ str(params[k])

        params_str += secretKey
        return hashlib.md5(params_str).hexdigest()
```

```PHP
/**
 * 生成签名信息
 * $secretKey 产品私钥
 * $params 接口请求参数，不包括signature参数
 */
function gen_signature($secretKey,$params){
    ksort($params);
    $buff="";
    foreach($params as $key=>$value){
        if($value !== null) {
           $buff .=$key;
           $buff .=$value;
        }
    }
    $buff .= $secretKey;
    return md5(mb_convert_encoding($buff, "utf8", "auto"));
}
```

```csharp
// 根据secretKey和parameters生成签名
public static String genSignature(String secretKey, Dictionary<String, String> parameters)
{
    parameters = parameters.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);

    StringBuilder builder = new StringBuilder();
    foreach (KeyValuePair<String, String> kv in parameters)
    {
        builder.Append(kv.Key).Append(kv.Value);
    }
    builder.Append(secretKey);
    String tmp = builder.ToString();
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(tmp));
    builder.Clear();
    foreach (byte b in result)
    {
        builder.Append(b.ToString("x2").ToLower());
    }
    return builder.ToString();
}
```

```js
var genSignature=function(secretKey,paramsJson){
    var sorter=function(paramsJson){
        var sortedJson={};
        var sortedKeys=Object.keys(paramsJson).sort();
        for(var i=0;i<sortedKeys.length;i++){
            sortedJson[sortedKeys[i]] = paramsJson[sortedKeys[i]]
        }
        return sortedJson;
    }
    var sortedParam=sorter(paramsJson);
    var needSignatureStr="";
    for(var key in sortedParam){
        var value=sortedParam[key];
        needSignatureStr=needSignatureStr+key+value;
    }
    needSignatureStr+=secretKey;
    var md5er = crypto.createHash('md5');//MD5加密工具
    md5er.update(needSignatureStr,"UTF-8");
    return md5er.digest('hex');
};
```