You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.0 KiB

聊天图片、文件消息接入

适用:企业与求职者的 DIRECT 会话。本文对应本批后端候选源码;尚未提交、推送或部署,线上 #94 还没有这些新接口。联调前确认本批已部署。

基础路径沿用项目 API_BASE_URL /api/v1。全部接口均要求 Authorization: Bearer <accessToken>,不能把 Token 放在 URL。现有文字、简历卡片接口保持原用法。普通 Emoji 仍走文字消息。

1. 上传并发送

POST /conversations/{id}/attachment-messages

请求类型 multipart/form-data,字段:

字段 必填 内容
file 是 一个文件;文件名和 MIME 必须正确
kind 是 IMAGE 或 FILE,大写
clientMessageId 是 客户端生成,1–64 位字母、数字、_、-

调用一次即上传并发送一条消息,没有单独“先上传再发 attachmentId”的步骤。使用项目现有鉴权请求封装;传 FormData 时不要手动写缺少 boundary 的 Content-Type。

成功:HTTP 200,沿用 {code:200,data:MessageResponse,requestId:...} 信封。IMAGE 和 FILE 消息都在既有 attachment 字段返回元数据。例如(示意数据):

{
  "id": 123,
  "clientMessageId": "image_abc123",
  "conversationId": 10,
  "senderUserId": 62,
  "messageType": "IMAGE",
  "content": "[图片]",
  "status": "SENT",
  "version": 1,
  "attachment": {
    "fileName": "office.png",
    "contentType": "image/png",
    "size": 18420,
    "sha256": "服务端实际保存图片的SHA256",
    "width": 1280,
    "height": 720,
    "available": true,
    "downloadPath": "/conversations/10/messages/123/attachment",
    "previewPath": "/conversations/10/messages/123/attachment/preview",
    "thumbnailPath": "/conversations/10/messages/123/attachment/thumbnail"
  }
}

FILE 的 previewPath、thumbnailPath、width、height 为空或省略。以上路径均相对 /api/v1,不是公开下载链接。不要自行拼接本地文件路径或对象存储地址。

文件范围

  • 图片:JPEG(.jpg/.jpeg)与 PNG;实际解码校验,最多 1600 万像素、任一边长不超过 8192。首版不支持 GIF、WebP、HEIC、SVG,前端选取时过滤或在明确告知后转换为支持格式。
  • 普通文件:PDF、DOC、DOCX、UTF-8 TXT;不支持 XLS/XLSX、ZIP、安装包或可执行文件。
  • 正确 MIME 分别为 image/jpeg、image/png、application/pdf、application/msword、application/vnd.openxmlformats-officedocument.wordprocessingml.document、text/plain。
  • 单文件最多 10 MiB(10,485,760 字节),空文件拒绝。会话有效附件默认累计最多 100 MiB。缩略图最长边 320,JPEG 格式。
  • 图片重新编码以移除 EXIF 等附加元数据,size/sha256 对应保存后的图片,可能与客户端原文件不同。
  • 文档执行扩展名、MIME、签名及 DOCX 压缩包结构检查;这不等于病毒扫描。

重试与错误

发送前生成 clientMessageId,网络超时后重试必须使用相同会话、账号、文件字节、文件名、MIME、kind 和 clientMessageId。相同请求返回原消息,不重复入库或推送;相同 key 改文件、改类型或与文字/简历消息混用返回 400。不要为一次自动重试重新生成 key。

  • HTTP 400:缺字段、非法类型、伪造内容、尺寸/业务大小超限、重复 key 内容不一致或会话配额耗尽;显示后端错误并保留重试/重新选择入口。
  • HTTP 413:Servlet 层拦截超大 multipart,请提示文件过大。
  • HTTP 401:未登录、会话失效或账号禁用。
  • HTTP 403:非成员、屏蔽、企业未认证、当前无有效投递沟通权限,或不是 DIRECT 会话。
  • HTTP 404:会话/消息不存在、附件已撤回/清除或发送者账号已禁用。

失败不能显示“已发送”。上传进度是否展示由前端传输层实现;当前后端不提供断点续传、分片或服务器进度接口。

2. 缩略图、预览和下载

接口 返回
GET /conversations/{conversationId}/messages/{messageId}/attachment 附件原始保存内容,Content-Disposition 为 attachment
GET .../attachment/preview 仅 IMAGE,重新编码的全尺寸图片,inline
GET .../attachment/thumbnail 仅 IMAGE,JPEG 缩略图,inline

均返回二进制,不经过 JSON 解包;响应头包括真实 Content-Type、Content-Length、Cache-Control: no-store 和 X-Content-Type-Options: nosniff。

列表优先加载 thumbnail,点击后鉴权加载 preview;文件消息显示 fileName、size 和下载操作。图片请求也要带 Authorization,不能只把受保护地址直接丢给不带鉴权的图片组件。

若先下载到 App 私有缓存再预览,应按账号隔离,退出账号、切换账号、撤回和失效时清除相关缓存;不要复制到公共相册或公共目录后仍宣称能被服务端撤回。已下载到设备或截图的内容,服务端不能远程收回。

每次下载重新检查会话成员、企业认证、有效沟通投递、屏蔽、消息状态和发送者有效性。列表里的 available:true 只代表列表读取时附件尚存,不保证之后每次请求仍获授权。

3. 消息列表、实时事件、撤回

现有 GET /conversations/{id}/messages 及 GET /conversations/{id}/events 会返回同样的 MessageResponse/attachment。WebSocket STOMP 的 MESSAGE_CREATED、MESSAGE_RECALLED 事件也使用同一结构。

  • 上传成功响应和实时事件可能都到达:按 message.id + version 合并,不能直接 append 两次。
  • 重连后使用既有游标补拉,补拉成功合并后才推进 nextCursor;不要用实时事件 eventId 直接覆盖补拉游标。
  • IMAGE/FILE 走对应气泡;保留 TEXT 和 RESUME 的现有渲染。
  • 撤回沿用 POST /conversations/{conversationId}/messages/{messageId}/recall:仅本人,沿用两分钟窗口。
  • 撤回成功后删除服务端原件/缩略图,消息保留“消息已撤回”,attachment.available=false,地址与元数据清空,前端停止展示/加载旧图。

4. 现有前端修改位置

  • app/chat/[id].tsx:把图片/文件按钮的占位提示替换为选择器;新增图片气泡、文件卡片、预览及下载反馈。
  • src/types/message.ts:扩展消息类型与 attachment 元数据,兼容无 attachment 的旧消息。
  • src/api/api.ts:multipart 发送、鉴权二进制请求与错误转换;所有请求沿用当前登录态。
  • src/hooks/useConversation.ts:发送状态、稳定 clientMessageId、重试、按 ID/版本合并、实时事件与重连补拉。

页面只处理展示和交互,请求与状态编排仍放在 API/Hook 层。地图功能不在本批范围。

5. 联调验收

  1. 企业、求职者在已允许沟通的投递内互发 PNG/JPEG/TXT/PDF,双方当前聊天页立即出现且不重复。
  2. 缩略图、全图、文件名/大小正确,下载字节与后端 sha256 一致;图片按服务端重新编码后的摘要核对。
  3. 超时重试复用 key,只产生一条;换文件复用同 key 被拒绝。
  4. 切账号、陌生账号、另一会话 ID、屏蔽、撤回、禁用账号无法继续读取附件。
  5. 接收方断网后重连补拉,退出重进及后端重启后历史附件仍在。
  6. 空文件、超限文件、伪装 PNG、非法文档和不支持格式均明确失败,页面无假成功或白屏。

6. 后端部署前提

需迁移 V62(新表 chat_attachments 与消息元数据列)。二进制在数据库中和消息一起提交,无需开放公开文件目录。MySQL max_allowed_packet 应至少 16 MiB,代理上传限制应允许约 11 MiB 的 multipart 请求;业务单文件仍受 10 MiB 限制。生产部署、代理配置修改需单独授权。

Servlet 上传边界至少为单文件 10 MiB、请求 11 MiB;既有更大的配置予以保留。会话业务配额可配置 app.chat.attachments.max-conversation-bytes(默认 104857600)。首次版本采用限额与撤回释放空间,尚无长期附件管理/任意时间删除接口。