服务端采集

服务端采集允许用户通过HTTP协议上传用户行为事件与用户属性

签名生成与验证

为了保障数据准确与安全,所有服务端数据采集需要通过签名验证才可以被接送。

签名生成原理:

  1. 上传的报文结构是嵌套的map结构如按照java的对象表示为Map<String,Object>

  2. 签名公式

a.【签名】 = MD5(JSON_ENCODE(【报文】)+ KEY )

b. 签名要求报文生成的json中的字段按照自然排序

i. 如java可以使用JSONObject.toJSONString(jsonObject, SerializerFeature.MapSortField),对字段进行自然排序

c. 加密key由交付团队提供

3. 签名实例(如下代码)

sign = JSONObject.toJSONString(jsonObject, SerializerFeature.MapSortField)+KEY;

生成签名字符串的demo

public class SignTest {
    @Test
    public static void signDemo() {
        String json = "JSON格式报文";
        JSONObject jsonObject = JSONObject.parseObject(json);
        System.out.println(JSONObject.toJSONString(jsonObject));
        //使用根据key进行字典排序,获取的JSON和key拼装进行签名
        System.out.println(JSONObject.toJSONString(jsonObject, SerializerFeature.MapSortField));
    }
}

签名验证流程图

接口调用DEMO

生成签名后,可以调用服务端接口上传数据。一下为事件报文的DEMO:

报文代码DEMO

{ 
  "sign":"27c95768438645138cfb010ded871091",  //必填,签名
  "tenant_id":"123456",      //必填,租户的id
  "appkey":"1344444",        //必填,应用appkey
  "id" : "get_coupons",      //必填,事件编码
  "umid" : "edfafs",         //选填,设备id,如果需要在路径分析理使用需要与客户端ID一致
  "puid" : "123456",         //选填,登录用户id,如果分析主体为“账号”,需要与SDK上传的登录ID一致
  "page_name":"home_page",    //选填,页面编码 
  "ts" : "1614667799165",    //必填,事件发生的时间戳,UNIX时间毫秒时间搓
  "cusp" : {                //事件自定义参数的KV
    "p1" : "1", // ”key" : "value"
    "p2" : "2",
    "p3" : "3"
  },
  "sdk_type":"httpapi",  // 固定值,采集服务自动加上该字段
}

接入代码Demo(依赖了fastjson以及okhttps)

package com.aliyun.app.quickaplus.mock.once_mock;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.aliyun.app.quickaplus.mock.util.MD5Util;
import okhttp3.*;

import java.io.IOException;

/**
 * 服务端ApiDemo
 *
 * @author chengtao
 */
public class ServiceApiDemo {


    /**
     * 收数域名
     */
    private static final String API_URL = "*****";

    /**
     * 服务器签名
     */
    private static final String SERVICE_KEY = "*******";


    /**
     * client日志
     */
    private static final OkHttpClient client = new OkHttpClient();

    /**
     * 主函数
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        String srcJsonString = getMockData();
        JSONObject json = JSON.parseObject(srcJsonString);
        //向报文中添加ts
        json.put("ts", String.valueOf(System.currentTimeMillis()));
        //计算签名
        String sign = MD5Util.md5(JSONObject.toJSONString(json, SerializerFeature.MapSortField) + SERVICE_KEY);
        json.put("sign", sign);
        String desJsonString = JSON.toJSONString(json, SerializerFeature.DisableCircularReferenceDetect);
        Request request = new Request.Builder()
                .url(API_URL + "/server-api")
                .post(RequestBody.create(desJsonString, MediaType.parse("application/json")))
                .build();
        try {
            Response response = client.newCall(request).execute();
            if (!response.isSuccessful()) {
                System.out.printf("[DEMO] 发送日志失败 %s%n", response);
            } else {
                System.out.printf("[DEMO] 发送成功 %s%n", response.body().string());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取MockData
     *
     * @return 返回值
     */
    private static String getMockData() {
        return "{\n" +
                "  \"tenant_id\": \"123456\",\n" +
                "  \"appkey\": \"1344444\",\n" +
                "  \"id\": \"get_coupons\",\n" +
                "  \"umid\": \"uuid()\",\n" +
                "  \"puid\": \"puid1\",\n" +
                "  \"page_name\": \"home_page\",\n" +
                "  \"cusp\": {\n" +
                "    \"p1\": \"1\",\n" +
                "    \"p2\": \"2\",\n" +
                "    \"p3\": \"3\"\n" +
                "  },\n" +
                "  \"sdk_type\": \"httpapi\"\n" +
                "}";
    }
}

返回值

{
  "message" : "上报成功",
  "code" : "Httpapi_300_200"
}

返回码(对应返回值结构中的code)

编号

类型

消息编码

消息文案

1

错误

Httpapi_300_101

非法的签名

2

Httpapi_300_102

上报日志非标准json格式

3

Httpapi_300_103

缺少必填字段

4

Httpapi_300_104

用户属性缺少必填字段

5

Httpapi_300_105

非法的事件id

6

成功

Httpapi_300_200

上报成功

报文协议

事件报文协议:使用此协议上传用户事件

{ 
  "sign":"27c95768438645138cfb010ded871091",  //必填,签名
  "tenant_id":"123456",      //必填,租户的id
  "appkey":"1344444",        //必填,应用appkey
  "id" : "get_coupons",      //必填,事件编码
  "umid" : "edfafs",         //选填,设备id
  "puid" : "123456",         //选填,登录用户id
  "page_name":"home_page",    //选填,页面编码 
  "ts" : "1614667799165",    //必填,事件发生的时间戳,UNIX时间搓,毫秒
  "cusp" : {                //事件自定义参数
    "p1" : "1",
    "p2" : "2",
    "p3" : "3"
  },
  "sdk_type":"httpapi",  // 固定值,采集服务自动加上该字段
  "sever_ts":"1614667799165",  // 采集服务采集日志时间戳,采集服务自动加上该字段
  "_id":'123344'         //日志唯一编码,采集服务自动加上该字段
}

属性报文协议:使用此协议上传用户属性

{ 
  "sign":"27c95768438645138cfb010ded871091",  //必填,签名
  "appkey":"1344444",        //选填,应用appkey,目前所有APP使用统一用户属性,不需填
  "id" : "$$_user_profile",     //必填,标识为用户属性,不能修改
  "umid" : "edfafs",         //选填,设备id
  "puid" : "123456",         //必填,登录用户id
  "ts" : "1614667799165",    //必填,事件发生的时间戳,UNIX时间搓,毫秒
   "cusp" : {                //必填,自定义用户属性
    "gender" : "1",             //性别
    "birthday" : "1988-12-24"  //出生年月
  },
  "sdk_type" : "httpapi",    //固定值,采集服务自动加上该字段
  "sever_ts":"1614667799165",  // 采集服务采集日志时间戳,采集服务自动加上该字段
  "log_id":'123344'         //日志唯一编码,采集服务自动加上该字段
 
}