10 KiB
10 KiB
Presence Service API 文档
概述
Base URL: /api/v1
所有需要认证的接口都需要在请求头中携带 JWT Token:
Authorization: Bearer <token>
1. 在线状态 API
1.1 记录心跳
记录用户心跳,更新在线状态。
请求
POST /api/v1/presence/heartbeat
Authorization: Bearer <token>
Content-Type: application/json
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| installId | string | 是 | 安装ID (8-64字符) |
| appVersion | string | 是 | 应用版本号 |
| clientTs | number | 是 | 客户端时间戳 (Unix秒) |
请求示例
{
"installId": "uuid-xxxx-xxxx-xxxx",
"appVersion": "1.0.0",
"clientTs": 1732685100
}
响应
{
"ok": true,
"serverTs": 1732685100123
}
| 字段 | 类型 | 描述 |
|---|---|---|
| ok | boolean | 是否成功 |
| serverTs | number | 服务器时间戳 (Unix毫秒) |
错误码
| HTTP 状态码 | 错误码 | 描述 |
|---|---|---|
| 400 | VALIDATION_ERROR | 参数校验失败 |
| 401 | UNAUTHORIZED | 未授权 |
1.2 查询在线人数
查询当前在线用户数量。
请求
GET /api/v1/presence/online-count
Authorization: Bearer <token>
查询参数
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
| windowSeconds | number | 否 | 180 | 时间窗口 (秒) |
响应
{
"count": 12345,
"windowSeconds": 180,
"queriedAt": "2025-01-01T12:00:00.000Z"
}
| 字段 | 类型 | 描述 |
|---|---|---|
| count | number | 在线用户数 |
| windowSeconds | number | 统计时间窗口 |
| queriedAt | string | 查询时间 (ISO 8601) |
1.3 查询在线人数历史
查询指定时间范围内的在线人数历史快照。
请求
GET /api/v1/presence/online-history
Authorization: Bearer <token>
查询参数
| 参数 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
| startTime | string | 是 | - | 开始时间 (ISO 8601) |
| endTime | string | 是 | - | 结束时间 (ISO 8601) |
| interval | string | 否 | 5m | 聚合间隔: 1m, 5m, 15m, 30m, 1h |
响应
{
"data": [
{
"ts": "2025-01-01T12:00:00.000Z",
"count": 12345
},
{
"ts": "2025-01-01T12:05:00.000Z",
"count": 12400
}
],
"interval": "5m",
"startTime": "2025-01-01T12:00:00.000Z",
"endTime": "2025-01-01T13:00:00.000Z",
"total": 12,
"summary": {
"max": 12500,
"min": 12000,
"avg": 12250
}
}
| 字段 | 类型 | 描述 |
|---|---|---|
| data | array | 快照数据列表 |
| data[].ts | string | 快照时间 |
| data[].count | number | 在线人数 |
| interval | string | 聚合间隔 |
| startTime | string | 实际开始时间 |
| endTime | string | 实际结束时间 |
| total | number | 数据点总数 |
| summary.max | number | 最大在线人数 |
| summary.min | number | 最小在线人数 |
| summary.avg | number | 平均在线人数 |
错误码
| HTTP 状态码 | 错误码 | 描述 |
|---|---|---|
| 400 | INVALID_TIME_RANGE | 无效的时间范围 |
| 400 | INVALID_INTERVAL | 无效的聚合间隔 |
2. 分析事件 API
2.1 批量上报事件
批量上报客户端分析事件。
请求
POST /api/v1/analytics/events
Content-Type: application/json
请求体
| 字段 | 类型 | 必填 | 描述 |
|---|---|---|---|
| events | array | 是 | 事件列表 |
| events[].eventName | string | 是 | 事件名称 (字母开头,1-64字符) |
| events[].installId | string | 是 | 安装ID |
| events[].userId | string | 否 | 用户ID (已登录用户) |
| events[].clientTs | number | 是 | 客户端时间戳 (Unix秒) |
| events[].properties | object | 否 | 事件属性 |
请求示例
{
"events": [
{
"eventName": "app_session_start",
"installId": "uuid-xxxx-xxxx-xxxx",
"userId": "12345",
"clientTs": 1732685100,
"properties": {
"os": "iOS",
"osVersion": "17.0",
"appVersion": "1.0.0",
"deviceModel": "iPhone 15 Pro",
"province": "广东省",
"city": "深圳市"
}
},
{
"eventName": "presence_heartbeat",
"installId": "uuid-xxxx-xxxx-xxxx",
"clientTs": 1732685160
}
]
}
响应
{
"accepted": 2,
"failed": 0,
"errors": []
}
| 字段 | 类型 | 描述 |
|---|---|---|
| accepted | number | 成功接收的事件数 |
| failed | number | 失败的事件数 |
| errors | array | 错误详情列表 |
预定义事件名称
| 事件名称 | 描述 |
|---|---|
| app_session_start | 应用会话开始 |
| app_session_end | 应用会话结束 |
| presence_heartbeat | 心跳事件 |
| user_login | 用户登录 |
| user_logout | 用户登出 |
2.2 查询日活统计
查询指定日期范围的日活统计数据。
请求
GET /api/v1/analytics/dau
Authorization: Bearer <token>
查询参数
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
| startDate | string | 是 | 开始日期 (YYYY-MM-DD) |
| endDate | string | 是 | 结束日期 (YYYY-MM-DD) |
响应
{
"data": [
{
"day": "2025-01-01",
"dauCount": 50000,
"dauByProvince": {
"广东省": 15000,
"北京市": 8000,
"上海市": 7000
},
"dauByCity": {
"深圳市": 10000,
"北京市": 8000,
"上海市": 7000
}
}
],
"total": 1,
"summary": {
"totalDau": 50000,
"avgDau": 50000,
"maxDau": 50000,
"minDau": 50000
}
}
| 字段 | 类型 | 描述 |
|---|---|---|
| data | array | 日活数据列表 |
| data[].day | string | 统计日期 |
| data[].dauCount | number | 日活人数 |
| data[].dauByProvince | object | 按省份统计 |
| data[].dauByCity | object | 按城市统计 |
| total | number | 数据天数 |
| summary | object | 汇总统计 |
错误码
| HTTP 状态码 | 错误码 | 描述 |
|---|---|---|
| 400 | INVALID_DATE_FORMAT | 无效的日期格式 |
| 400 | DATE_RANGE_TOO_LARGE | 日期范围过大 (最多90天) |
3. 健康检查 API
3.1 健康检查
检查服务健康状态。
请求
GET /api/v1/health
响应
{
"status": "ok",
"service": "presence-service",
"timestamp": "2025-01-01T12:00:00.000Z"
}
4. 错误响应格式
所有错误响应遵循统一格式:
{
"statusCode": 400,
"path": "/api/v1/presence/heartbeat",
"method": "POST",
"message": "installId must be a string",
"timestamp": "2025-01-01T12:00:00.000Z"
}
| 字段 | 类型 | 描述 |
|---|---|---|
| statusCode | number | HTTP 状态码 |
| path | string | 请求路径 |
| method | string | 请求方法 |
| message | string | 错误信息 |
| timestamp | string | 错误时间 |
ValidationPipe 错误格式
当请求体校验失败时,message 字段可能为数组:
{
"statusCode": 400,
"path": "/api/v1/presence/heartbeat",
"method": "POST",
"message": [
"installId must be a string",
"clientTs must be a number"
],
"timestamp": "2025-01-01T12:00:00.000Z"
}
5. 通用 HTTP 状态码
| 状态码 | 描述 |
|---|---|
| 200 | 请求成功 |
| 201 | 资源创建成功 |
| 400 | 请求参数错误 |
| 401 | 未授权 |
| 403 | 禁止访问 |
| 404 | 资源不存在 |
| 422 | 业务逻辑错误 |
| 500 | 服务器内部错误 |
6. 限流策略
| 接口 | 限制 | 窗口 |
|---|---|---|
| POST /heartbeat | 60 次/分钟/用户 | 滑动窗口 |
| POST /events | 100 次/分钟/IP | 滑动窗口 |
| GET /online-count | 120 次/分钟/用户 | 滑动窗口 |
| GET /online-history | 30 次/分钟/用户 | 滑动窗口 |
| GET /dau | 30 次/分钟/用户 | 滑动窗口 |
超出限制返回 429 Too Many Requests。
7. SDK 示例
JavaScript/TypeScript
class PresenceClient {
private baseUrl: string;
private token: string;
constructor(baseUrl: string, token: string) {
this.baseUrl = baseUrl;
this.token = token;
}
async sendHeartbeat(installId: string, appVersion: string): Promise<void> {
const response = await fetch(`${this.baseUrl}/api/v1/presence/heartbeat`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`,
},
body: JSON.stringify({
installId,
appVersion,
clientTs: Math.floor(Date.now() / 1000),
}),
});
if (!response.ok) {
throw new Error(`Heartbeat failed: ${response.status}`);
}
}
async getOnlineCount(windowSeconds = 180): Promise<number> {
const response = await fetch(
`${this.baseUrl}/api/v1/presence/online-count?windowSeconds=${windowSeconds}`,
{
headers: {
'Authorization': `Bearer ${this.token}`,
},
}
);
const data = await response.json();
return data.count;
}
}
cURL 示例
# 发送心跳
curl -X POST https://api.example.com/api/v1/presence/heartbeat \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"installId": "uuid-xxxx-xxxx-xxxx",
"appVersion": "1.0.0",
"clientTs": 1732685100
}'
# 查询在线人数
curl https://api.example.com/api/v1/presence/online-count \
-H "Authorization: Bearer <token>"
# 查询在线历史
curl "https://api.example.com/api/v1/presence/online-history?startTime=2025-01-01T00:00:00Z&endTime=2025-01-01T12:00:00Z&interval=5m" \
-H "Authorization: Bearer <token>"
# 批量上报事件
curl -X POST https://api.example.com/api/v1/analytics/events \
-H "Content-Type: application/json" \
-d '{
"events": [
{
"eventName": "app_session_start",
"installId": "uuid-xxxx-xxxx-xxxx",
"clientTs": 1732685100,
"properties": {"os": "iOS"}
}
]
}'