Files
IM_NEW/API.md
T

25 KiB
Raw Blame History

IM_API_NEW 接口文档

基于微服务架构的即时通讯系统,包含 6 个独立 WebApi 服务。

通用说明

统一响应格式 Result<T>

{
  "code": 0,
  "message": "成功",
  "data": { }
}
  • code:业务状态码,0 表示成功(见下方状态码表)
  • message:状态描述
  • data:业务数据,失败时为 null

认证

除特别说明外,所有接口需在请求头携带 JWT:

Authorization: Bearer {token}

当前用户 ID 从 Token 的 NameIdentifier 声明中获取,无需在请求体重复传递。

路由约定

控制器统一采用 api/[controller]/[action] 路由模板(FileService 例外,见对应章节)。


1. 认证服务 (User.WebApi - Auth)

以下接口无需认证

POST /api/Auth/Login — 登录

请求体:

字段 类型 必填 说明
userName string 5-20 字符
password string ≤50 字符

响应:Result<LoginResponse>

请求示例:

{
  "userName": "zhangsan",
  "password": "P@ssw0rd"
}

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "userId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refreshToken": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "expired": "2026-06-27T10:30:00Z",
    "userName": "zhangsan",
    "nickName": "张三",
    "avatar": "https://cdn.example.com/avatar/zhangsan.png",
    "creationTime": "2026-01-15T08:00:00+00:00"
  }
}

失败示例(密码错误,code 2002):

{
  "code": 2002,
  "message": "密码错误",
  "data": null
}

POST /api/Auth/Register — 注册

请求体:

字段 类型 必填 说明
userName string 5-20 字符
password string 6-50 字符
nickName string ≤50 字符

响应:Result<UserResponse>

请求示例:

{
  "userName": "zhangsan",
  "password": "P@ssw0rd",
  "nickName": "张三"
}

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "userName": "zhangsan",
    "nickName": "张三",
    "email": null,
    "phone": null,
    "region": "",
    "description": "",
    "avatar": null,
    "creationTime": "2026-06-26T08:00:00+00:00",
    "deletion": null
  }
}

POST /api/Auth/Refresh — 刷新令牌

请求体:

字段 类型 必填 说明
refreshToken string 刷新令牌

响应:Result<LoginResponse>

请求示例:

{
  "refreshToken": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
}

响应示例:同 Login 的 Result<LoginResponse>

LoginResponse 结构

{
  "userId": "guid", "token": "string", "refreshToken": "string",
  "expired": "datetime", "userName": "string", "nickName": "string",
  "avatar": "string|null", "creationTime": "datetime"
}

2. 用户服务 (User.WebApi - User)

需认证。

GET /api/User/Me — 当前用户信息

响应:Result<UserResponse>

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "userName": "zhangsan",
    "nickName": "张三",
    "email": "zhangsan@example.com",
    "phone": "13800000000",
    "region": "广东·深圳",
    "description": "这个人很懒,什么都没写",
    "avatar": "https://cdn.example.com/avatar/zhangsan.png",
    "creationTime": "2026-01-15T08:00:00+00:00",
    "deletion": null
  }
}

GET /api/User/Find?userId={guid} — 查询指定用户

响应:Result<UserResponse>(结构同上)

GET /api/User/FindByUname?username={string} — 按用户名查询

响应:Result<UserResponse>(结构同上)

POST /api/User/Update — 更新资料

请求体(均可选):nickNameregionavatardescription 响应:Result<UserResponse>

请求示例:

{
  "nickName": "张三丰",
  "region": "湖北·武当山",
  "avatar": "https://cdn.example.com/avatar/new.png",
  "description": "太极宗师"
}

POST /api/User/GetUsersByIds — 批量查询用户

请求体:["guid", "guid"]Guid 数组) 响应:Result<List<UserResponse>>

请求示例:

[
  "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
  "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d"
]

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": [
    { "id": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b", "userName": "zhangsan", "nickName": "张三", "email": null, "phone": null, "region": "广东·深圳", "description": "", "avatar": null, "creationTime": "2026-01-15T08:00:00+00:00", "deletion": null }
  ]
}

UserResponse 结构

{
  "id": "guid", "userName": "string", "nickName": "string",
  "email": "string|null", "phone": "string|null", "region": "string",
  "description": "string", "avatar": "string|null",
  "creationTime": "datetime", "deletion": "datetime|null"
}

3. 联系人服务 (ContactService.WebApi)

需认证。

好友 (Friend)

方法 路径 说明 参数
GET /api/Friend/List 好友列表 -
POST /api/Friend/Delete 删除好友 friendId (query)
POST /api/Friend/Block 拉黑好友 friendId (query)
GET /api/Friend/CheckFriend 检查好友关系 userId, targetId (query)

GET /api/Friend/List 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": [
    {
      "id": "e5f6a7b8-c9d0-1e2f-3a4b-5c6d7e8f9a0b",
      "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "avatar": "https://cdn.example.com/avatar/lisi.png",
      "nickName": "李四",
      "remarkName": "老李",
      "createTime": "2026-02-01T10:00:00",
      "updateTime": null,
      "status": "Pending"
    }
  ]
}

POST /api/Friend/Delete?friendId={guid} 响应示例:

{ "code": 0, "message": "成功", "data": true }

GET /api/Friend/CheckFriend?userId={guid}&targetId={guid} 响应示例:

{ "code": 0, "message": "成功", "data": true }

好友请求 (FriendRequest)

POST /api/FriendRequest/Add — 发起好友申请

字段 类型 必填 说明
targetId guid 被申请人
description string 附言
remarkName string 备注名

请求示例:

{
  "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "description": "我是张三,加个好友",
  "remarkName": "老李"
}

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "c1d2e3f4-a5b6-7c8d-9e0f-1a2b3c4d5e6f",
    "ownerId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "ownerNickName": "张三",
    "ownerAvatar": "https://cdn.example.com/avatar/zhangsan.png",
    "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "targetNickName": "李四",
    "targetAvatar": "https://cdn.example.com/avatar/lisi.png",
    "description": "我是张三,加个好友",
    "state": "Pending",
    "remarkName": "老李",
    "creationTime": "2026-06-26T09:00:00+00:00",
    "deletion": null,
    "modificationTime": null
  }
}

POST /api/FriendRequest/Handle — 处理申请

字段 类型 必填 说明
requestId guid 请求 ID
action string "Accpet" 同意, "Reject" 拒绝, "Block" 拉黑
remarkName string 同意时必填 备注名

请求示例:

{
  "requestId": "c1d2e3f4-a5b6-7c8d-9e0f-1a2b3c4d5e6f",
  "action": "Accpet",
  "remarkName": "张三"
}

响应示例:

{ "code": 0, "message": "成功", "data": true }

GET /api/FriendRequest/List — 我相关的申请列表

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": [
    {
      "id": "c1d2e3f4-a5b6-7c8d-9e0f-1a2b3c4d5e6f",
      "ownerId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
      "ownerNickName": "张三",
      "ownerAvatar": "https://cdn.example.com/avatar/zhangsan.png",
      "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "targetNickName": "李四",
      "targetAvatar": "https://cdn.example.com/avatar/lisi.png",
      "description": "我是张三,加个好友",
      "state": "Passed",
      "remarkName": "老李",
      "creationTime": "2026-06-26T09:00:00+00:00",
      "deletion": null,
      "modificationTime": "2026-06-26T09:05:00+00:00"
    }
  ]
}

FriendRequestResponse 状态 (State)"Pending" 待通过, "Declined" 已拒绝, "Passed" 已同意, "Blocked" 已拉黑


4. 群组服务 (GroupService.WebApi)

需认证(GroupMember 部分接口除外)。

群组 (Group)

方法 路径 说明 参数
GET /api/Group/GetAll 我加入的群列表 -
GET /api/Group/GetOne 群详情 groupId (query)
POST /api/Group/Create 创建群 body: name (≤20)
POST /api/Group/Update 更新群 body: 见下

Update 请求体:

字段 类型 必填
groupId guid
groupName string
avatar string
description string

POST /api/Group/Create 请求示例:

{ "name": "技术交流群" }

POST /api/Group/Update 请求示例:

{
  "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
  "groupName": "技术交流群(2026)",
  "avatar": "https://cdn.example.com/group/tech.png",
  "description": "欢迎交流技术"
}

GET /api/Group/GetOne?groupId={guid} 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "name": "技术交流群",
    "groupMaster": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "authority": "REQUIRE_CONSENT",
    "allMembersBanned": false,
    "status": "Normal",
    "announcement": "欢迎加入",
    "avatar": "https://cdn.example.com/group/tech.png",
    "maxSequenceId": 1024,
    "lastMessage": "晚上好",
    "lastSenderName": "张三",
    "created": "2026-03-01T08:00:00+00:00",
    "updated": "2026-06-26T09:00:00+00:00"
  }
}

群成员 (GroupMember)

方法 路径 说明 参数
GET /api/GroupMember/CheckMember 检查成员 userId, groupId (query)
GET /api/GroupMember/List 成员列表 groupId (query)
POST /api/GroupMember/Delete 移除成员 memberId (query)

GET /api/GroupMember/List?groupId={guid} 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": [
    {
      "id": "f1e2d3c4-b5a6-9788-1a2b-3c4d5e6f7a8b",
      "userId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
      "groupNickName": "群主张三",
      "avatar": "https://cdn.example.com/avatar/zhangsan.png",
      "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
      "role": "Master",
      "created": "2026-03-01T08:00:00+00:00"
    }
  ]
}

成员角色 (Role)"Normal" 普通成员, "Administrator" 管理员, "Master" 群主

群邀请 (GroupInvitation)

方法 路径 说明 参数
POST /api/GroupInvitation/Send 发送邀请 body: groupId, userId
GET /api/GroupInvitation/Get 邀请详情 invitationId (query)
POST /api/GroupInvitation/Handle 处理邀请 invitationId, action (query)

POST /api/GroupInvitation/Send 请求示例:

{
  "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
  "userId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d"
}

GET /api/GroupInvitation/Get?invitationId={guid} 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e",
    "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "groupAvatar": "https://cdn.example.com/group/tech.png",
    "groupName": "技术交流群",
    "userId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "userAvatar": "https://cdn.example.com/avatar/lisi.png",
    "userNickName": "李四",
    "operatorId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "operatorName": "张三",
    "operatorAvatar": "https://cdn.example.com/avatar/zhangsan.png",
    "state": "Pending",
    "created": "2026-06-26T09:00:00+00:00",
    "updated": "2026-06-26T09:00:00+00:00"
  }
}

邀请处理 action"Accept" 接受, "Reject" 拒绝 邀请状态 (State)"Pending" 待被邀请人同意, "Passed" 已同意, "Reject" 拒绝

入群请求 (GroupRequest)

方法 路径 说明 参数
POST /api/GroupRequest/Send 申请入群 body: groupId, desc (≤20)
POST /api/GroupRequest/Handle 处理申请 requestId, action (query)
GET /api/GroupRequest/Find 申请详情 id (query)
GET /api/GroupRequest/List 申请列表 -

POST /api/GroupRequest/Send 请求示例:

{
  "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
  "desc": "我想加入学习"
}

GET /api/GroupRequest/Find?id={guid} 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "c3d4e5f6-a7b8-9c0d-1e2f-3a4b5c6d7e8f",
    "groupId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
    "groupAvatar": "https://cdn.example.com/group/tech.png",
    "groupName": "技术交流群",
    "userId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "userAvatar": "https://cdn.example.com/avatar/lisi.png",
    "userNickName": "李四",
    "operatorId": "00000000-0000-0000-0000-000000000000",
    "operatorName": "",
    "operatorAvatar": null,
    "state": "Pending",
    "description": "我想加入学习",
    "created": "2026-06-26T09:00:00+00:00",
    "updated": "2026-06-26T09:00:00+00:00"
  }
}

入群处理 action"Accept" 接受, "Reject" 拒绝 入群状态 (State)"Pending" 待管理员同意, "Declined" 已拒绝, "Passed" 已通过

群权限 (Authority)"REQUIRE_CONSENT" 需管理员同意, "ANYONE_CAN_JOIN" 任意人可加, "NOT_ALLOWED_TO_JOIN" 不允许加入 群状态 (Status)"Normal" 正常, "Blocked" 封禁


5. 消息服务 (MessageService.WebApi)

需认证。

会话 (Conversation)

方法 路径 说明 参数
GET /api/Conversation/List 会话列表 -
GET /api/Conversation/Get 会话详情 id (query)
POST /api/Conversation/MarkRead 清零未读 conversationId (query)

GET /api/Conversation/List 响应示例:

{
  "code": 0,
  "message": "成功",
  "data": [
    {
      "id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
      "userId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
      "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "targetAvatar": "https://cdn.example.com/avatar/lisi.png",
      "targetName": "李四",
      "lastReadSequenceId": 1020,
      "unreadCount": 4,
      "chatType": "PRIVATE",
      "lastMessage": "晚上一起吃饭吗?",
      "dateTime": "2026-06-26T18:30:00"
    }
  ]
}

POST /api/Conversation/MarkRead?conversationId={guid} 响应示例:

{ "code": 0, "message": "成功", "data": null }

消息 (Message)

POST /api/Message/Send — 发送消息

字段 类型 必填 说明
clientMsgId guid 客户端消息 ID(去重)
targetId guid 接收方(单聊=用户,群聊=群)
chatType string "PRIVATE" 单聊, "GROUP" 群聊
msgType string 见消息类型表
quoteMessageId guid 引用消息 ID
ext object 扩展字段 (键值对)
text string 文本内容
url string 媒体 URL
width / height int 图片/视频尺寸
thumb string 缩略图
duration int 时长(语音/视频)

文本消息请求示例:

{
  "clientMsgId": "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
  "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "chatType": "PRIVATE",
  "msgType": "Text",
  "text": "晚上一起吃饭吗?"
}

图片消息请求示例:

{
  "clientMsgId": "8f9a0b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c",
  "targetId": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
  "chatType": "GROUP",
  "msgType": "Image",
  "url": "https://cdn.example.com/img/photo.jpg",
  "width": 1920,
  "height": 1080,
  "thumb": "https://cdn.example.com/img/photo_thumb.jpg",
  "quoteMessageId": "1c2d3e4f-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
  "ext": { "source": "album" }
}

发送响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "9a0b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
    "clientMsgId": "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
    "chatType": "PRIVATE",
    "msgType": "Text",
    "senderId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "state": "Sent",
    "streamKey": "stream:private:xxx",
    "sequenceId": 1021,
    "creationTime": "2026-06-26T18:35:00+00:00",
    "content": {
      "fallback": "晚上一起吃饭吗?",
      "body": { "text": "晚上一起吃饭吗?" },
      "ext": {},
      "quote": null
    }
  }
}

POST /api/Message/WithDraw — 撤回消息 参数:msgId (query)

响应示例:

{ "code": 0, "message": "成功", "data": true }

GET /api/Message/GetMessages — 拉取消息

参数 类型 说明
conversationId guid 会话 ID
cursor long? 游标
direction int 方向
limit int 数量

请求示例:

GET /api/Message/GetMessages?conversationId=d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a&cursor=1021&direction=0&limit=20

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "messages": [
      {
        "id": "9a0b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
        "clientMsgId": "7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b",
        "chatType": "PRIVATE",
        "msgType": 0,
        "senderId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
        "targetId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
        "state": "Sent",
        "streamKey": "stream:private:xxx",
        "sequenceId": 1021,
        "creationTime": "2026-06-26T18:35:00+00:00",
        "content": { "fallback": "晚上一起吃饭吗?", "body": { "text": "晚上一起吃饭吗?" }, "ext": {}, "quote": null }
      }
    ],
    "hasmore": true
  }
}

消息类型 (MsgType)"Text" 文本, "Image" 图片, "Voice" 语音, "Video" 视频, "File" 文件, "VoiceChat" 语音通话, "VideoChat" 视频通话 会话类型 (ChatType)"PRIVATE" 单聊, "GROUP" 群聊


6. 文件服务 (FileService.WebApi)

需认证。路由为 api/Fileapi/FileTask

文件 (File) — 小文件直传/下载

POST /api/File/simple-upload — 单次直传(头像/封面等),支持秒传

  • Content-Type: multipart/form-data
  • 表单字段:file (文件), isPublic (booltrue 落公开桶返回直链)
  • 秒传:服务端计算文件 MD5 后,若已存在相同 checksum 的文件则直接返回已有记录,跳过存储写入
  • 响应:Result<FileResponse>

请求示例(form-data):

file: (二进制文件)
isPublic: true

秒传命中响应(与正常上传返回一致,但实际未写入存储):

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d",
    "ownerId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "fileName": "avatar.png",
    "fileSize": 20480,
    "contentType": "image/png",
    "state": "Uploaded",
    "storageLocation": {
      "storageProvider": "local",
      "bucket": "im-public",
      "objectKey": "2026/06/26/abc123.png",
      "region": "local"
    },
    "checkSum": "d41d8cd98f00b204e9800998ecf8427e",
    "created": "2026-06-26T09:00:00+00:00",
    "updated": "2026-06-26T09:00:00+00:00",
    "url": "https://cdn.example.com/public/avatar.png"
  }
}

正常上传响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "id": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d",
    "ownerId": "8f3a2c10-1b2c-4d5e-9a8b-7c6d5e4f3a2b",
    "fileName": "avatar.png",
    "fileSize": 20480,
    "contentType": "image/png",
    "state": "Uploaded",
    "storageLocation": {
      "storageProvider": "local",
      "bucket": "im-public",
      "objectKey": "2026/06/26/abc123.png",
      "region": "local"
    },
    "checkSum": "d41d8cd98f00b204e9800998ecf8427e",
    "created": "2026-06-26T09:00:00+00:00",
    "updated": "2026-06-26T09:00:00+00:00",
    "url": "https://cdn.example.com/public/avatar.png"
  }
}

GET /api/File/{id} — 获取文件信息(含直链 Url,私有文件 Url 为 null 响应:Result<FileResponse>(结构同上;私有文件 urlnull

GET /api/File/{id}/content — 鉴权下载文件内容(私有文件预览/下载) 响应:文件流 (File 结果,二进制;非 Result<T> 包装)

分片上传任务 (FileTask) — 大文件分片

完整流程:Init → GetUploadUrl → UploadPart → Complete(四步) 支持秒传、分片大小校验、上传进度查询。

POST /api/FileTask/init — 初始化上传任务(支持秒传)

字段 类型 说明
conversationId guid 会话 ID
fileName string 文件名
fileSize long 文件大小(≤ 1GB,由 MaxObjectSizeBytes 控制)
contentType string MIME 类型
checkSum string 校验和(必须,用于秒传去重)

请求示例:

{
  "conversationId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f9a",
  "fileName": "movie.mp4",
  "fileSize": 104857600,
  "contentType": "video/mp4",
  "checkSum": "9e107d9d372bb6826bd81d3542a419d6"
}

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "taskId": "b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e",
    "uploadSessionId": "sess_abc123",
    "storageLocation": {
      "storageProvider": "local",
      "bucket": "im-local",
      "objectKey": "data/im-files/2026/06/27/movie.mp4",
      "region": "local"
    }
  }
}

秒传命中(checksum 匹配已完成的文件,跳过初始化):

{
  "code": 0,
  "message": "成功",
  "data": {
    "taskId": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d",
    "uploadSessionId": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d",
    "storageLocation": {
      "storageProvider": "local",
      "bucket": "im-local",
      "objectKey": "2026/06/26/existing.png",
      "region": "local"
    }
  }
}

此时 taskId 即为已存在文件的 ID,前端可直接跳到 Complete。

文件过大失败:

{ "code": 2402, "message": "文件大小超限", "data": null }

GET /api/FileTask/Getuploadurl — 获取分片上传地址 参数:sessionId, partNum (query)

  • partNum 必须满足 1 ≤ partNum ≤ totalPartCount,越界返回 3206(无效分片号)

请求示例:

GET /api/FileTask/Getuploadurl?sessionId=sess_abc123&partNum=1

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": "https://oss.example.com/upload?sessionId=sess_abc123&partNum=1&signature=xxx"
}

GET /api/FileTask/progress查询上传进度(新增) 参数:sessionId (query)

请求示例:

GET /api/FileTask/progress?sessionId=sess_abc123

响应示例:

{
  "code": 0,
  "message": "成功",
  "data": {
    "sessionId": "sess_abc123",
    "taskId": "b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e",
    "fileSize": 104857600,
    "totalPartCount": 20,
    "completedPartCount": 7,
    "uploadedBytes": 36700160,
    "progressPercent": 35
  }
}

POST /api/FileTask/complete — 完成上传(合并分片)

字段 类型 说明
sessionId string 会话 ID
parts UploadPart[] 分片列表(必须与 totalPartCount 数量一致

分片数量不匹配返回 3204(分片数量不匹配)。

请求示例:

{
  "sessionId": "sess_abc123",
  "parts": [
    { "partNumber": 1, "eTag": "etag-part-1", "size": 5242880 },
    { "partNumber": 2, "eTag": "etag-part-2", "size": 5242880 }
  ]
}

响应示例:Result<FileResponse>(结构同 simple-upload

POST /api/FileTask/local/parts/upload — 本地分片上传(支持分片大小校验) 表单字段:sessionId, partNumber, file

  • 非末片大小 ≥ MinPartSizeBytes(默认 5MB),否则返回 3203(分片过小)
  • 末片豁免最小值校验

请求示例(form-data):

sessionId: sess_abc123
partNumber: 1
file: (二进制分片)

附录:业务状态码表

范围 分类 示例
0 成功 0 成功
1000-1999 系统级 1003 参数错误, 1005 权限不足, 1006 认证失败
2000-2099 用户 2000 用户不存在, 2001 用户已存在, 2002 密码错误
2100-2199 好友 2100 好友申请已存在, 2102 已经是好友
2200-2299 群聊 2200 群不存在, 2201 已在群中, 2202 群成员已满
2300-2399 消息 2300 发送失败, 2301 消息不存在, 2302 撤回失败
2400-2499 文件 2400 上传失败, 2401 文件不存在, 2402 大小超限
3000-3099 管理后台 3000 管理员不存在, 3003 权限不足
3100-3199 会话 3100 会话不存在
3200-3299 分片 3201 分片不存在, 3202 分片合并失败, 3203 分片过小, 3204 分片数不匹配, 3205 会话过期, 3206 分片号无效