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.
 
 
 

7.5 KiB

个人头像与公司 Logo:前端对接

日期:2026-10-27。本文面向前端开发与联调人员;本批只改后端和契约,不表示已部署或前端已经接入。

1. 展示规则

场景 数据来源 无图片时
本人的个人资料/本人聊天气泡 GET /auth/me 的 avatarUrl 个人昵称首字
聊天对方为求职者 会话列表/详情的 avatarUrl contactName 首字
聊天对方为企业 会话列表/详情的 avatarUrl,来源为公司 logoUrl 公司名称首字
企业主页、岗位关联公司卡片 企业资料的 logoUrl 公司名称首字

个人头像属于用户,Logo 属于企业,两个资源独立。企业账号修改个人头像不改变公司 Logo;修改 Logo 不改变 HR 本人头像。不要根据 URL 是否为空自行把个人头像替换成企业 Logo,或反过来。

本人的头像以 /auth/me 为统一来源,本批不改变 GET /profile/me 的空资料返回 {} 约定。会话摘要实时查询用户/公司引用,不从历史消息中固化头像。TALENT_INVITATION 会话继续隐藏候选人个人头像,不因新上传接口而放开隐私。

2. 上传、删除与读取接口

以下路径相对于 API 基址 /api/v1。所有写请求使用当前账号 access token,身份来自服务端,不接受客户端 userId/companyId 或文件路径。

方法 路径 权限/作用
POST /auth/me/avatar 已选择身份且有效的 STUDENT/COMPANY/ADMIN;上传自己的个人头像
DELETE /auth/me/avatar 同上;清空个人头像,重复删除成功
POST /companies/me/logo COMPANY 且已有自己的企业资料;上传企业 Logo
DELETE /companies/me/logo 同上;清空企业 Logo,重复删除成功
GET /profile-images/{imageId} 公司 Logo 可匿名读;个人头像须鉴权且仅本人或具备当前 DIRECT 沟通授权的成员可读

企业不必先通过认证才能维护自己的 Logo,但上传 Logo 不改变企业认证状态,也不放开岗位发布门禁。

上传请求

multipart/form-data,字段名 file。使用 FormData,不要手动设置 Content-Type(让运行时自动带 boundary),不要把本机 file:// URI 或预设素材 key 作为远程图片 URL 提交。

允许 JPEG/PNG(扩展名、声明 MIME 与真实解码格式必须匹配),原文件最多 2 MiB;单边最多 4096、总像素最多 400 万。SVG/GIF/WebP/HEIC 等本批不支持。相册素材不满足格式时应在客户端转换并裁剪,或给出明确提示。

后端去除原图元数据及附加内容,等比例缩小到最长边 512,透明背景转白色,统一保存 JPEG,最大 512 KiB。文件名和原图不保存。

成功返回 envelope,data 示例:

{
  "url": "/api/v1/profile-images/00000000-0000-0000-0000-000000000000",
  "version": "00000000-0000-0000-0000-000000000000",
  "contentType": "image/jpeg",
  "size": 12345
}

示例 UUID 仅示意;每次上传生成新 UUID 和新 URL。个人上传同时更新 users.avatar_url;Logo 上传更新 companies.logo_url。替换/删除在数据库事务内完成,失败保留旧图与旧引用;不推进在线简历 revision。

删除成功 data 为 {"deleted":true}。重新取资料时没有头像/Logo 应使用占位图,不能继续展示旧本地缓存。

图片读取

url 是包含 API context path 的同源相对路径,不是完整域名。用 API 服务 origin 解析,不要再次拼 /api/v1,也不要让已登录下载器向任意外部 URL 附带 Bearer。

个人头像 GET 必须带 Authorization: Bearer access-token;普通图片组件不会必然继承业务请求层的鉴权,要给同源 source 配置认证请求头,或通过受控下载层取字节。禁止把 Token 拼进 URL。

返回 image/jpeg,Cache-Control: no-store,X-Content-Type-Options: nosniff。这是图片字节,不是 JSON,不能直接使用只解 JSON envelope 的 request() 当作图片下载器。

旧 URL 在替换/删除后返回 404。第三方登录账号即使知道私有头像 URL,也不能读取;具备 DIRECT 成员关系还必须满足当前拉黑、撤回及企业接收投递等沟通权限。公司 Logo 是公开企业展示素材,不能用它上传私密资料。

错误状态

  • 400:文件缺失、空文件、格式/MIME/内容不一致、大小或像素超限。
  • 401:缺少/无效/过期/禁用的登录凭证;匿名读个人头像。
  • 403:身份不允许、非授权聊天成员、已失去沟通权限。
  • 404:企业资料不存在、图片不存在/已替换/已删除、图片所属账号停用。
  • 超出全局 multipart/网关大小上限可能更早被拒绝;前端仍应先限制 2 MiB。

不要向用户暴露文件系统路径、SQL、Token 或完整异常日志。

3. 缓存与状态同步

  1. 上传成功立即把返回的新 URL 更新到本人资料状态;更新会话页共享状态或使会话列表/详情缓存失效。
  2. 个人资料页与聊天页复用图片头像组件。先尝试图片 URL,失败/缺失才回退姓名首字;不能把 URL 渲染到 Text。
  3. 页面重新聚焦时拉取当前 /auth/me、会话列表/详情,避免长期使用路由传参或首次进入时的旧快照。
  4. 对方设备不会因为本机 setState 自动更新。本批没有新增头像变更 WebSocket 事件;对方通过列表/详情刷新获取新 URL。若要求停留聊天页时即时更新,需要前端刷新策略或另立头像事件协议。
  5. 旧图收到 404 时只做受控的元信息刷新,不能无限重试旧 URL。新 URL 成功后覆盖显示,失败时使用占位头像。
  6. 切换账号时清理身份相关状态及私有图片缓存;上一账号迟到的响应不能覆盖新账号。

本机历史 file://、本地预设头像不自动迁移到后端。需要前端获得可上传的实际文件并调用上传接口;只在个人资料页选中素材不算服务器保存成功。

4. 联调验收

  • 求职者改头像后:个人资料、本人气泡、对方会话列表/详情使用同一新图。
  • 企业改个人头像不改公司 Logo;改 Logo 后企业主页、岗位公司卡片和对方会话摘要使用新 Logo。
  • 换设备/重新登录仍能从服务器读取;成功上传前不提示“已同步”。
  • 连续替换、删除、并发上传均只保留当前版本;旧 URL 不再可读。
  • 匿名/第三方账号不可读私有头像;合法 DIRECT 成员可读,拉黑后旧 URL 也不可读;邀约隐私保持。
  • 测试空文件、假图片、MIME 伪装、超限、旧地址404与加载失败占位。
  • 全流程不改变在线简历内容和 revision,不混用公司 Logo 和个人头像。

5. 存储与验收边界

新增 V63 迁移,仅创建 profile_images 表,不重写旧迁移,不搬运历史外链。每个 owner/kind 最多一张当前图片,二进制和引用在同一数据库事务内更新;数据库备份需包含该表。账号注销完成时清除其上传图片,物理删除用户/企业时外键级联清理。

现有企业资料中的历史 logoUrl 外链保持兼容;后端不会下载/代理任意外部图片。历史资料接口另写 logoUrl 后,已不再引用的新上传地址不可读;推荐统一使用本批上传/删除接口维护图片。

本轮定向验证结果见同目录 profile-images-development-verification-20261027.md。全量 clean verify、双真实 MySQL、同次 JAR 黑盒与重启,以及前端真机验收须按各自实际结果登记,不能以此文档替代通过证据。