rwadurian/backend/services/presence-service/docs/API.md

10 KiB
Raw Blame History

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"}
      }
    ]
  }'