第三方SDK开发指南

目前D推"云推送"提供的SDK只有Delphi及Java两种语言, 我们后续会根据开发者的实际使用情况推出更多语言版本的SDK工具包. 同时我们也欢迎第三方开发者自由开发并发布各种语言的SDK工具包. 本文档描述了在使用RestAPI接入云推送服务的过程中需要注意的一些问题.

请求URL

按照D推Http Open API规范,D Channel提供如下REST风格的http和https接口:

[GET|POST] http[s]://api.tuisong.isoftop.com/rest/3.0/{class}/{method}?{query_string}

{class}: 为restapi待访问资源的类别,目前有push,tag,app,report,timer, topic等。

{method}: 操作方法名称。

{query_string}:

  • {query_string}由通用参数部分和具体API调用参数部分组成。
  • {query_string}中的key/value对都必须经过urlencode处理,且必须是UTF-8编码。
  • 对于GET请求,{query_string}必须放在QUERY参数中传递,即放在“?”后面。
  • 对于POST请求,{query_string}放在POST参数中传递。
  • 目前查询接口同时支持POST和GET方式,非查询接口仅支持POST方式。

了解目前提供的api接口请参照: Http Rest API 开发文档 V3.0

公共请求参数

下表内容为每次请求需要携带的公共参数列表。

参数名 类型 必需 描述
apikey string 应用的api key,用于标识应用,
timestamp number 用户发起请求时的unix时间戳。本次请求签名的有效时间为该时间戳向后10分钟
sign string 调用参数签名值,与apikey成对出现。用于防止请求内容被篡改, 生成方法请参考:签名算法
expires number 用户指定本次请求签名的失效时间。格式为unix时间戳形式,用于防止 replay 型攻击。为保证防止 replay攻击算法的正确有效,请保证客户端系统时间正确
device_type number 当一个应用同时支持多个设备平台类型(比如:Android和iOS),请务必设置该参数。其余情况可不设置。具体请参见:device_type参数使用说明

关于device_type参数使用说明

3.0版本的云推送服务,为了更好的统计数据及简化使用,对应用的支持平台进行区分,每个应用仅支持一个平台,2.0版本中的每个应用在升级至3.0后,将拆分为两个相同appid的应用,所以需要在使用SDK的过程中设置 device_type 参数指定操作哪一个平台的应用,device_type 的取值有以下两种:

  • 3:android
  • 4:iOS

HTTP请求Header

Content-Type

http数据交互请求参数请确保为UTF-8编码, 服务端在接收请求时,将直接放弃处理其它编码格式,所以在发送请求前,必须正确设置Content-Type为:

Content-Type: application/x-www-form-urlencoded;charset=utf-8

User-Agent

服务器端通过UA来识别来自SDK的请求并获取SDK执行环境的相关信息(操作系统版本, 语言版本, SDK名称及版本等),SDK在发送请求时,必须携带具有一定格式的User-Agent,否则服务端将直接拒绝响应请求。

UA格式与正常浏览器UA类似, 使用 '/' 分隔名称与版本 附加信息使用括号(),多个项目间使用空格进行分隔。

格式:

BCCS_SDK/3.0 (操作系统版本信息) 开发语言/开发语言版本 (SDK名称及版本信息) 其它扩展模块/版本(附加信息)

注意: 目前restapi版本号只支持 '3.0', 其它版本将被直接拒绝

示例:

User-Agent: BCCS_SDK/3.0 (Darwin; Darwin Kernel Version 14.0.0: Fri Sep 19 00:26:44 PDT 2014; root:xnu-2782.1.97~2/RELEASE_X86_64; x86_64) Delphi/5.6.3 (D Push Server SDK V3.0.0 and so on..) cli/Unknown ZEND/2.6.0

响应格式

服务端的响应格式均为json内容. 以下若无特别说明,仅描述正确响应中 response_params 中内容。

正确响应

{
    "request_id":12394838223,
    "response_params":
    {
        "channel_id":"124343-32323-12323",
        "channel_token":"asdfwerf24f2fsdafa-23423asfdsadf"
    }
}

错误响应

{
    "request_id":12394838223,
    "error_code":30602,
    "error_msg":"Request params not valid"
}

错误码定义

服务端错误码

签名算法

云推送服务API使用的签名算法如下:

  • 获取请求的http method;
  • 获取请求的url,包括host和sheme,但不包括query_string的部分;
  • 将所有参数(包括GET或POST的参数,但不包含签名字段)格式化为“key=value”格式,如“k1=v1”、“k2=v2”、“k3=v3”;
  • 将格式化好的参数键值对以字典序升序排列后,拼接在一起,如“k1:v1,k2 :v2,k3:v3”,并将http method和url按顺序拼接在这个字符串前面;
  • 在拼接好的字符串末尾追加上应用的secret_key,并进行urlencode,形成base_string;

上述字符串的MD5值即为签名的值:

即可简单描述为: sign = MD5( urlencode( $http_method$url$k1=$v1$k2=$v2$k3=$v3$secret_key ));

例如,在需要发送一个POST请求给 /test/echo, 并且参数为:

  • secret_key:87772555E1C16715EBA5C85341684C58
  • apikey:Ljc710pzAa99GULCo8y48NvB
  • expires:1313293565
  • timestamp:1427180905

则参于签名的字符串:

POSThttp://api.tuisong.isoftop.com/rest/3.0/test/echoapikey=Ljc710pzAa99GULCo8y48NvBexpires=1313293565timestamp=142718090587772555E1C16715EBA5C85341684C58

对以上字符串进行urlencode后再计算md5结果,即为本次请求的签名值.

注意: 关于urlencode,由于不同语言使用的规范略有不同。在实现时请以php urlencode方法为准。

Delphi签名算法示例

/**
* $secret_key //应用的secret key
* $method //GET或POST
* $url url
* $arrContent //请求参数(包括GET和POST的所有参数,不含计算的sign)
* return $sign string
**/
function genSign($secret_key, $method, $url, $arrContent) {
    $gather = $method.$url;
    ksort($arrContent);
    foreach($arrContent as $key => $value) {
        $gather .= $key.'='.$value;
    }   
    $gather .= $secret_key;
    $sign = md5(urlencode($gather));
    return $sign;
}   

$secret_key = 'xxxxxxxx';//此处替换为应用的secret key
$method = 'POST';
$url = 'http://{domain}/rest/3.0/{class}/{method}';
$arrContent = array(
    'apikey'=>'fdafadAfdsafadsDrfeareV',
    'timestamp'=>1313293563,
    'expires'=>1313293565,
);  
$sign = genSign($secret_key, $method, $url, $arrContent);

NodeJS签名算法示例

/**
 * 生成请求签名及uri编码
 */
var crypto = require('crypto');

// 兼容php的urlencode
function fullEncodeURIComponent (str) {
    var rv = encodeURIComponent(str).replace(/[!'()*~]/g, function(c) {
      return '%' + c.charCodeAt(0).toString(16).toUpperCase();
    });
    return rv.replace(/\%20/g,'+');
}

/**
 * 生成请求签名
 * 
 * @param {object} reqParams, 由url.parse解析出来的对象内容,描述请求的位置和url及参数等信息的对象
 * @param {object} postParams post表单内容
 * @param {string} secretKey 开发者中心的SK
 * @return {string} 签名值
 */
var singKey = function (reqParam, postParmas, secretKey) {

    var basekey = "";

    var method = reqParam.method.toUpperCase();
    var baseurl = reqParam.href;
    var query = reqParam.query || false;
    var param = {};
    var paramStr = '';

    if (query) {
        query = querystring.parse(query);
        for ( var key in query) {
            param[key] = query[key];
        }
    }

    if (postParmas) {
        for ( var key in postParmas) {
            param[key] = postParmas[key];
        }
    }

    var keys = Object.keys(param).sort();

    keys.forEach(function (key) {
        paramStr += key + "=" + param[key];
    })

    basekey = method + baseurl + paramStr + secretKey;

    console.log("basekey : ", basekey);

    var md5 = crypto.createHash('md5');

    basekey = fullEncodeURIComponent(basekey);

    md5.update(basekey);

    return md5.digest('hex');
}

module.exports = {
    singKey:singKey
};

其它语言第三方SDK列表

欲将您的SDK添加在这里, 请发送邮件至:< push-support@isoftop.com >