# 接口导入

## 数据接口

### 功能描述

调用该接口，把符合特定格式的数据以POST的方式上报至数据接收服务器。接收服务器对上报的数据进行校验，不符合格式的返回相应的错误提示。易观SDK就是通过该API进行数据上报。

上报后的数据会先暂存在 Kafka 中，流处理引擎大约会以3000条/秒的速度将数据落库并可用于查询，该过程性能受服务器影响，但偏差一般不会太大。

### 接口协议

HTTP(S)，POST方式

### 请求地址

```
http(s)://host:port/up
```

### 请求数据

请求的 Body 体里面存放具体要上报的数据，数据明文为 JsonArray 的形式。上报的数据明文示例如下：

```javascript
[{
    "appid": "demo",
    "xwho": "8c0eebf0-2383-44bc-b8ba-a5c719fc6194",
    "xwhat": "confirmOrder",
    "xwhen": 1532514947857,
    "xcontext": {
        "$channel": "豌豆荚",
        "$app_version": "4.0.4.001",
        "$model": "MI 6X",
        "$os": "Android",
        "$os_version": "8.1.0",
        "$lib": "Android",
        "$platform": "Android",
        "$is_login": false,
        "$lib_version": "4.0.4",
        "$debug": 2,
        "$importFlag": 1     //说明：$importFlag字段是专门用作导数
    }
}]
```

### 数据编码

请使用 UTF-8 编码。上报数据可以使用明文上报，也可以对数据进行压缩/编码处理后进行上报。压缩/编码过程具体为：先进行Gzip压缩，然后进行Base64编码，最后把编码后的数据直接放到Body体里面上报即可。

### 应答格式

* 上报成功：{"code":200}
* 上报失败：{"code":500}
* 上报数据格式错误：{"code":xxx, "msg":"xxxxx"}，返回的应答消息中包含"msg"字段，内容为具体的异常信息。

API调用参考示例

```
String uploadUrl = "http://ip:port/up";
StringBuffer buffer = new StringBuffer();
buffer.append("[{");
buffer.append("\"appid\":\"demo\",");
buffer.append("\"xwho\":\"8c0eebf0-2383-44bc-b8ba-a5c719fc6194\",");
buffer.append("\"xwhat\":\"confirmOrder\",");
buffer.append("\"xwhen\":1532514947857,");
buffer.append("\"xcontext\":{");
buffer.append("\"$channel\":\"豌豆荚\",");
buffer.append("\"$app_version\":\"4.0.4.001\",");
buffer.append("\"$model\":\"MI6X\",");
buffer.append("\"$os\":\"Android\",");
buffer.append("\"$os_version\":\"8.1.0\",");
buffer.append("\"$lib\":\"Android\",");
buffer.append("\"$platform\":\"Android\",");
buffer.append("\"$is_login\":false,");
buffer.append("\"$lib_version\":\"4.0.4\",");
buffer.append("\"$debug\":2,");
buffer.append("\"$importFlag\":1");
buffer.append("}");
buffer.append("}]");
String uploadJsonData = buffer.toString();

/*// 对数据进行压缩/编码(可选)
String gzipUploadJsonData = GZIPInputStreamUtil.encode(uploadJsonData); // GZIP压缩
String base64UploadJsonData = Base64Util.encode(gzipUploadJsonData);    // Base64编码
uploadJsonData = base64UploadJsonData;*/

CloseableHttpClient httpclient = HttpClients.createDefault();
    try {
        HttpPost httpPost = new HttpPost(uploadUrl);
        StringEntity req = new StringEntity(uploadJsonData);
        req.setContentEncoding("UTF-8");
        httpPost.setEntity(req);
        httpclient.execute(httpPost);
        } catch (Exception e) {
            exceptionHandle(e);
        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                logger.errot(e);
            }
        }
```

{% hint style="info" %}
没有特殊需求的情况下，不建议使用该API直接上报数据。推荐使用SDK进行数据上报，SDK有完善的数据校验等功能，更安全可靠。
{% endhint %}

## 数据格式及约束

数据上报需要符合一定的格式以及规范。服务器会对上报的数据做有效性校验，不符合规范的数据会返回给调用方错误信息。

### 字段说明

&#x20;**上报报文必须包含`xwho`/`xwhat`/`xwhen`/`appid`/`xcontext`这几个key，具体含义如下：**

appid：字符串，等价于一个产品，推荐跨平台使用。

{% hint style="danger" %}
appid为该产品特有的标识，非法值或恶意篡改的值上报至服务器会返回错误。

Appid等于`Appkey`可以在统计平台-项目管理中获取
{% endhint %}

xwho：字符串，长度大于0且小于255字符。不可以为中文。 用户定义的用户唯一性标准 xwhat：字符串， 需要符合Java命名规则： 开头约束:字母或者$ 字符类型:大小写字母、数字、下划线和 $ 最大长度是99字符。不可以为中文。任何主体主动/被动触发事件的的事件名除内置预定义事件外，其他事件全部来源用户。主要分为三种类型: 用户事件(Profile/User)，可以修改；普通事件(Event/Track) ，不允许修改；预置事件，不建议用户覆盖，但是可以强行覆盖。&#x20;

xwhen：数字型(Long类型)，事件触发的时间。默认使用本地时间，但是需要将时区信息放到xcontext中。

xcontext：JSON格式，数据结构是KV结构。主要包含: 描述信息。所有事件xcontext中必须包含五个字段: $platform、$lib、$is\_login、$lib\_version、$debug 以及 $importFlag。

$importFlag：数值型，值为1，必填。用于告诉方舟该条数据是历史数据，不做时间窗口校验并且允许进行查询。

$lib：字符串，SDK类型，选项有:Java、Python、JS、Node、PHP、Wechat、Andorid、iOS。

$platform：字符串，平台信息，和lib相同；也可自定义添加平台信息。

$lib\_version：字符串，SDK版本号

$debug： 数值型，是否为DEBUG模式。&#x20;

> 三个选项：
>
> 0==非debug
>
> 1==debug不入库
>
> 2==debug入库

$is\_login：布尔值，用于标识该事件是否有已登录用户产生

### 支持类型

上报报文的Json数据结构中的Key值类型如下：

符合java命名规则： 开头约束:字母或者$ 字符类型:大小写字母、数字、下划线和 $ 最大长度125字符 上报报文的Json数据结构中的value值类型如下：

`Number` ：int/long/double/float&#x20;

`Boolean` ：数据传输中使用true/false,后端处理转换为0,1&#x20;

`String`：字符串,后端支持时间格式: DATE/DATETIME&#x20;

`Array`：类型 List、数组(这种格式的:\[]),传输给服务器全部转化为JSONArray

### 约束条件

上报的json中的key以及xwhat的value值需要符合Java命名规则。

`key/xwhat的value约束`: 以字母或$开头，可包含大小写字母/数字/\_/$，最大长度125字符，不支持乱码和中文

`xwhat`的value值最大长度是99字符

`id`限制：长度大于0且小于255字符

`xcontext`约束：

`key约束：`符合java命名规则： 开头约束:字母或者$ 字符类型:大小写字母、数字、下划线和 $ 最大长度125字符

`value约束：` 类型约束(String/Number/boolean/list/数组)，若为字符串，最大长度255

`个数约束：` xcontext中承载的属性设置最大个数是300个。数组集合约束 数组或集合内最多包含100条。 若为字符串数组或集合，每条最大长度255个字符。

### 预置事件

事件名称，即xwhat值。可以理解成：某一个体在某一时间点的状态。 当触发相应接口时，只发送相关数据，没有设备信息。用户属性是一个标准的K-V结构，K和V均有相应的约束条件，如不符合则丢弃该次操作。&#x20;

> **参数约束**
>
> 属性名：以字母或$开头,可包含大小写字母/数字/\_/$,最大长度125字符,不支持乱码和中文
>
> 属性值：支持部分类型：String/Number/boolean/集合/数组; 若为字符串,则最大长度255字符; 若为数组或集合,则最多包含100条,且key约束条件与属性名称一致,value最大长度255字符。

#### 用户类型事件

有以下几种类型：

`$profile_set`: 给用户设置单个或多个属性，比如用户的年龄/性别等信息。如果之前不存在，则新建，否则覆盖。

上传报文示例：

```javascript
[{
    "xwhen": 1532756553883,
    "xcontext": {
        "$lib": "Android",
        "$debug": 0,
        "$is_login": true,
        "userPoint": 0,
        "userLevel": 0,
        "interest": ["户外活动", "足球赛事", "游戏"],
        "nickName": "昵称123",
        "$lib_version": "4.0.3",
        "$platform": "Android"
    },
    "appid": "1234",
    "xwho": "ABCDEF123456789",
    "xwhat": "$profile_set"
}]
```

&#x20;`$profile_set_once:`设置用户的固有属性，只在首次设置时有效的属性。如：用户的注册时间。如果被设置的用户属性已存在，则这条记录会被忽略而不会覆盖已有数据，如果属性不存在则会自动创建。上传报文示例：

```javascript
[{
	"xwhen": 1532756655466,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"registerTime": "20180101101010",
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$profile_set_once"
}]
```

`$profile_unset`: 删除某个已设置的用户属性。上传报文示例：

```javascript
[{
	"xwhen": 1532757129288,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"nickName": "",
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$profile_unset"
}]
```

`$profile_increment`:设置用户属性的相对变化值(相对增加，减少)，只能对数值型属性进行操作，携带参数必须为 Number类型。如果这个Profile之前不存在,则初始值为0。上传报文示例：

```javascript
[{
	"xwhen": 1532756825695,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"userPoint": 20,
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$profile_increment"
}]
```

`$profile_append`: 用户列表属性增加元素，上行协议的值为Array结构。为列表类型的属性增加一个或多个元素，如：用户新增兴趣爱好。上传报文示例：

```javascript
[{
	"xwhen": 1532757076341,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"interest": ["户外活动", "足球赛事", "游戏"],
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$profile_append"
}]
```

$profile\_delete:删除全部已设置的用户属性。上传报文示例：

```javascript
[{
	"xwhen": 1532757239032,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"$platform": "Android",
		"$lib_version": "4.0.3"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$profile_delete"
}]
```

身份关联：该场景一般应用在用户注册/登录的过程中。比如：一个匿名用户浏览商品，系统为其分配的DistinctId = "1234567890987654321"，随后该匿名用户进行注册，系统为其分配了新的注册ID，aliasId = "ABCDEF123456789"，此时就需要调用alias接口对两个ID进行关联。

`$alias`:关联身份, 计算时会认为是一个用户的行为。上传报文示例：

```javascript
[{
	"xwhen": 1532757366067,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"$original_id": "1234567890987654321",
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$alias"
}]
```

#### &#xD;系统启动/页面事件

$pageview：浏览页面，打开页面时触发

```javascript
[{
	"xwhen": 1532757366067,
	"xcontext": {
		"$lib": "Android",
		"$debug": 0,
		"$is_login": true,
		"$original_id": "1234567890987654321",
		"$lib_version": "4.0.3",
		"$platform": "Android"
	},
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$alias"
}]
```

&#x20;`$startup`：安装后，首次启动事件。上传报文示例：

```javascript
[{
	"appid": "1234",
	"xwho": "ABCDEF123456789",
	"xwhat": "$startup",
	"xwhen": 1532687468414,
	"xcontext": {
		"$is_first_time": false,
		"$is_from_background": false,
		"$channel": "测试",
		"$manufacturer": "Xiaomi",
		"$app_version": "1.0",
		"$model": "MIX 2S",
		"$os": "Android",
		"$os_version": "8.0.0",
		"$network": "WIFI",
		"$screen_width": 1080,
		"$screen_height": 2030,
		"$brand": "Xiaomi",
		"$is_first_day": true,
		"$lib": "Android",
		"$platform": "Android",
		"$is_login": false,
		"$lib_version": "4.0.4",
		"$debug": 2
	}
}]
```

### 数据上报示例

以下示例是追踪一个匿名用户浏览商品，然后注册系统后再次浏览商品，然后生成订单，最后支付的流程

```java
String appid = "1234";
String service_url = "http://host:port/up;
String distinctId = "1234567890987654321"; //用户匿名ID
//浏览商品
StringBuffer buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + distinctId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"ViewProduct\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"$ip\":\"112.112.112.112\",");
buffer.append("       \"productName\":[\"Thinking in Java\"],");
buffer.append("       \"productType\":\"Java书籍\",");
buffer.append("       \"producePrice\":80,");
buffer.append("       \"shop\":\"xx网上书城\",");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":false,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
//用户注册登录
buffer = new StringBuffer();
String registerId = "ABCDEF123456789";
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"$alias\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0,");
buffer.append("       \"$original_id\":\"" + distinctId + "\"");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
//用户信息
buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"$profile_set\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0,");
buffer.append("       \"nickName\":\"昵称123\",");
buffer.append("       \"userLevel\":0,");
buffer.append("       \"userPoint\":0,");
buffer.append("       \"interest\":[\"户外活动\",\"足球赛事\",\"游戏\"]");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
//用户注册时间
buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"$profile_set_once\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0,");
buffer.append("       \"registerTime\":\"20180101101010\"");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());

//再次浏览商品
buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"ViewProduct\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"$ip\":\"112.112.112.112\",");
buffer.append("       \"productName\":[\"Thinking in Java\"],");
buffer.append("       \"productType\":\"Java书籍\",");
buffer.append("       \"producePrice\":80,");
buffer.append("       \"shop\":\"xx网上书城\",");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
//订单信息
buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"Order\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"orderId\":\"ORDER_12345\",");
buffer.append("       \"price\":80,");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
//购买商品
buffer = new StringBuffer();
buffer.append("[{");
buffer.append("   \"xwho\":\"" + registerId + "\",");
buffer.append("   \"xwhen\":\"" + System.currentTimeMillis() + "\",");
buffer.append("   \"xwhat\":\"Payment\",");
buffer.append("   \"appid\":\"" + appid + "\",");
buffer.append("   \"xcontext\":{");
buffer.append("       \"orderId\":\"ORDER_12345\",");
buffer.append("       \"price\":80,");
buffer.append("       \"productNumber\":\"AliPay\",");
buffer.append("       \"paymentMethod\":80,");
buffer.append("       \"productName\":[\"Thinking in Java\"],");
buffer.append("       \"productType\":\"Java书籍\",");
buffer.append("       \"producePrice\":80,");
buffer.append("       \"$platform\":\"Android\",");
buffer.append("       \"$lib\":\"Android\",");
buffer.append("       \"$is_login\":true,");
buffer.append("       \"$lib_version\":\"0.1.0\",");
buffer.append("       \"$debug\":0");
buffer.append("   }");
buffer.append("}]");
postDataToServer(service_url, buffer.toString());
```

以上各个流程对应的上报的JSON明文如下：

浏览商品：

```javascript
[{
	"xwho": "1234567890987654321",
	"xwhen": "1532683122298",
	"xwhat": "ViewProduct",
	"appid": "1234",
	"xcontext": {
		"$ip": "112.112.112.112",
		"productName": ["Thinking in Java"],
		"productType": "Java书籍",
		"producePrice": 80,
		"shop": "xx网上书城",
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": false,
		"$lib_version": "0.1.0",
		"$debug": 0
	}
}]
```

用户注册登录：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "$alias",
	"appid": "1234",
	"xcontext": {
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0,
		"$original_id": "1234567890987654321"
	}
}]
```

用户信息：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "$profile_set",
	"appid": "1234",
	"xcontext": {
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0,
		"nickName": "昵称123",
		"userLevel": 0,
		"userPoint": 0,
		"interest": ["户外活动","足球赛事","游戏"]
	}
}]
```

用户注册时间：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "$profile_set_once",
	"appid": "1234",
	"xcontext": {
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0,
		"registerTime": "20180101101010"
	}
}]
```

再次浏览商品：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "ViewProduct",
	"appid": "1234",
	"xcontext": {
		"$ip": "112.112.112.112",
		"productName": ["Thinking in Java"],
		"productType": "Java书籍",
		"producePrice": 80,
		"shop": "xx网上书城",
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0
	}
}]
```

订单信息：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "Order",
	"appid": "1234",
	"xcontext": {
		"orderId": "ORDER_12345",
		"price": 80,
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0
	}
}]
```

购买商品：

```javascript
[{
	"xwho": "ABCDEF123456789",
	"xwhen": "1532683122298",
	"xwhat": "Payment",
	"appid": "1234",
	"xcontext": {
		"orderId": "ORDER_12345",
		"price": 80,
		"productNumber": "AliPay",
		"paymentMethod": 80,
		"productName": ["Thinking in Java"],
		"productType": "Java书籍",
		"producePrice": 80,
		"$platform": "Android",
		"$lib": "Android",
		"$is_login": true,
		"$lib_version": "0.1.0",
		"$debug": 0
	}
}]
```

{% hint style="info" %}
以上内容没有解答我的问题？[点击我进入方舟论坛去反馈](https://www.analysysdata.com/forum/index) 🚀
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://arkdocs.analysys.cn/integration/import/restful-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
