1. V1接口通用说明
1.1.1. 调用限制
访问 微丰 开放接口(v1),需要遵循以下规则:
- 所有API都是为服务器端调用设计,请不要在客户端(Web前端页面、手机应用等调用),否则可能会存在鉴权泄漏的风险。
 - 常规API默认的频次限制为 60次/分钟,所以任何API在1分钟内最多可调用60次。
 - 统计分析类API由于涉及计算量较大,仅支持单线程串行调用,禁止并发调用。
 
1.1.2. 调用格式
HTTP方法
微丰开放接口(v1)可能会使用到以下HTTP方法:
- GET:用于获取数据的接口
 - POST:用于创建接口
 - PUT:用于修改接口
 - DELETE:用于删除接口
 
我们会在每个接口的文档中注明所使用的 HTTP 方法,调用接口时请以具体的接口文档为准。
调用地址
微丰开放接口的调用地址都符合以下格式之一:
https://[saas子域名].wefeng360.com/api/v1/[接口相对地址]?[URL参数]×tamp=[时间戳]&sign=[签名]
OR
https://[个性化域名+前缀]/api/v1/[接口相对地址]?[URL参数]×tamp=[时间戳]&sign=[签名]
其中被中括号包含部分的含义如下:
| 变量 | 说明 | 
|---|---|
| saas子域名 | 您访问微丰系统被分配的专属二级域名 | 
| 个性化域名+前缀 | 您访问微丰私有化系统的个性化二级域名和前缀 | 
| 接口相对地址 | 您调用的具体API的相对URL,会在每个API中注明 | 
| URL参数 | 接口所需的Query String参数 | 
| 时间戳 | 发起请求时的时间戳,格式为Unix Time,即从“1970-01-01 00:00:00”至今的秒数 | 
| 签名 | 身份验证签名,除非明确说明,否则每次API调用都需要携带,计算方法参见下文 [鉴权方法] | 
每个接口文档中都会给出类似以下的调用方法: GET /customers 其中包含了 HTTP 方法及接口相对地址,其他部分则需要根据具体情况替换。
参数
接口文档中可能会出现以下三种参数类型:
- URL 中:嵌入在调用地址中的参数,如
/customers/:id中的:id; - Query String:调用地址 Query String 部分的参数,如
/customers?page=2中的page; - Request Body:请求体中的内容。 当调用创建、修改类接口时,需要将请求数据按照 JSON 格式转换为 UTF-8 文本,将编码后的字符串作为 Request Body 类参数传给对应的接口。 同时将请求头中的 Content-Type 字段设置为 application/json 。
 
返回结果
- 微丰开放接口(v1)的返回数据同样为JSON格式格式编码的 UTF-8 字符串。
 - 微丰开放接口在Response的header中会返回X-Request-Id标识一次唯一请求,如需微丰工程师协助定位接口调用疑问,请务必提供Response中的X-Request-Id。
 
1.1.3. 鉴权方法
规则说明
所有接口调用需要携带签名参数 sign,只有当 sign 值合法时请求才会被接受。 sign 的计算方法如下:
sign=SHA256(secretKey×tamp)
其中:
- secretKey 为租户秘钥,在微丰系统后台系统对接处获取;
 - timestamp 为Unix time,即从“1970-01-01 00:00:00”至今的秒数。
 - 注:timestamp有效期为10分钟
 
示例
假设要调用以下接口:
https://[调用域名]/api/v1/external_contact/:externalUserId
鉴权所需数据如下:
| 名称 | 数据 | 
|---|---|
| secretKey | 5480583a6494445897pa3s1241 | 
| timestamp | 1619143576 | 
计算sign:
sha256("5480583a6494445897pa3s1241&1619143576")
27aa4b58a5eff9d006c974d62a4b0837e1be1cc90e5a3578aeadbe61d4914220
最终请求URL:
https://[调用域名]/api/v1/external_contact/wm_3b_XXXXXX?sign=fbdd2e45e3bd9d1f1e4915863cff62c2d6f901490070741b821ad55d7e231552×tamp=1619143576
python3示例
from hashlib import sha256
import time
if __name__ == '__main__':
    secrekey = "5480583a6494445897pa3s1241"
    timestamp = str(int(time.time()))
    key = str(secrekey + '&' + timestamp)
    sign = sha256(key.encode("utf-8")).hexdigest()
    print(sign)
java示例
public class SignUtil {
  public static String createSign(String timestamp, String appKey) {
    String signStr = appKey + "&" + timestamp;
    return createSignWithStr(signStr);
  }
  public static String createSignWithStr(String signStr) {
    String sign = null;
    MessageDigest instance;
    try {
      instance = MessageDigest.getInstance("SHA-256");
      instance.update(signStr.getBytes());
      sign = byte2Hex(instance.digest());
    } catch (Exception e) {
      log.error("生成接口签名失败!", e);
    }
    return sign;
  }
  /**
   * 将byte转为16进制
   *
   * @param bytes
   * @return
   */
  private static String byte2Hex(byte[] bytes) {
    StringBuffer stringBuffer = new StringBuffer();
    String temp = null;
    for (int i = 0; i < bytes.length; i++) {
      temp = Integer.toHexString(bytes[i] & 0xFF);
      if (temp.length() == 1) {
        //1得到一位的进行补0操作
        stringBuffer.append("0");
      }
      stringBuffer.append(temp);
    }
    return stringBuffer.toString();
  }
}