9.3 KiB
个人头像云端维护
Makelore 个人资料模块 · 服务端接口与联调说明
| 项目 | 内容 |
|---|---|
| 文档状态 | 服务端接口已完成,待客户端联调 |
| 目标读者 | 用户服务、文件存储、API 开发人员 |
| 客户端约束 | 客户端统一将头像裁剪为正方形,界面以圆形蒙版展示 |
联调前置
- 部署服务端时,先执行 Alembic 迁移:
20260813_user_avatar_cloud_0040。 - 新客户端只使用以下接口:
POST /api/user/avatar、DELETE /api/user/avatar、GET /api/user/agent-profile。 - 旧接口
/api/auth/me/avatar仅保留兼容,新客户端不要继续使用。
1. 需求概述
Makelore 个人资料弹窗需要支持用户维护个人头像,并将头像按账号保存到云端。用户可在个人资料中上传、替换或移除头像;保存后,头像应在不同设备间同步。
**核心结论:**头像通过独立接口维护。服务端提供上传、删除接口,并在个人资料查询响应中返回只读字段 avatar_url;avatar_url 不得放入 Agent Profile 的 PUT 请求体。
2. 产品范围与行为
- 头像展示位置:侧边栏底部账号按钮、展开后的账号菜单、个人资料弹窗预览。聊天消息布局本期不增加用户头像。
- 上传格式:PNG、JPEG、WebP。客户端会在上传前自动居中裁剪为正方形,并压缩到最长边 512px。
- 展示方式:客户端使用圆形蒙版展示头像;服务端不需要保存圆形遮罩图,保存正方形图片即可。
- 保存时机:用户选择图片或点击移除后只更新弹窗草稿;点击“保存个人资料”时才调用上传或删除接口。
- 默认头像:没有头像或头像加载失败时,客户端回退显示用户姓名首字母。
- 账号隔离:头像必须绑定当前登录用户,不允许通过请求参数指定其他用户。
- URL 生命周期:OSS 环境下
avatar_url为 24 小时有效的签名 URL,客户端启动或刷新资料时重新获取。 - URL 使用方式:客户端直接使用服务端返回的
avatar_url,不得持久化为永久地址,不得自行拼接、截断、改写或刷新签名参数。
3. 接口总览
| 方法 | 上游路径 | 用途 | 成功结果 |
|---|---|---|---|
GET |
/api/user/agent-profile |
查询个人资料 | 返回 avatar_url 字段 |
POST |
/api/user/avatar |
上传或替换头像 | 返回新的 avatar_url |
DELETE |
/api/user/avatar |
删除当前头像 | 返回 avatar_url: null |
**路径说明:**上表是服务端上游接口路径。客户端通过 Electron Main 的 Host API 代理访问,服务端无需感知客户端的本地代理路径。
4. 认证与通用约定
- 所有接口使用现有登录态认证:
Authorization: Bearer <access_token>。 - 用户身份从 access token 解析,不接受
user_id、username等客户端字段作为头像归属依据。 - 成功响应直接返回 JSON 对象;头像 URL 字段统一命名为只读响应字段
avatar_url。 avatar_url只能出现在个人资料查询、上传成功和删除成功响应中,不能出现在 Agent Profile 的 PUT 请求体中。- OSS 环境下
avatar_url是 24 小时签名 URL;客户端应直接将其用于头像展示,不得持久化为永久地址,也不得自行拼接或修改 URL。 - 接口失败时沿用项目现有错误响应结构,并返回稳定错误码。
5. 接口详细要求
5.1 扩展个人资料查询
现有接口保持不变,在返回的个人资料对象中提供只读字段 avatar_url。客户端启动和刷新资料时都应重新调用该接口,获取新的签名 URL。
GET /api/user/agent-profile
Authorization: Bearer <access_token>
成功响应示例:
{
"display_name": "小明",
"age": 18,
"gender": "male",
"avatar_url": "https://oss.example.com/avatars/user-1-v3.webp?X-Amz-Expires=86400&X-Amz-Signature=<signature>",
"share_age_with_agents": true,
"share_gender_with_agents": true,
"analysis_enabled": true,
"completed": true,
"version": 3,
"updated_at": "2026-08-13T00:00:00Z"
}
无头像时必须返回 null,而不是省略字段:
{
"avatar_url": null
}
5.2 上传或替换头像
POST /api/user/avatar
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
请求表单字段:
| 字段名 | 类型 | 必填 | 要求 |
|---|---|---|---|
file |
File |
是 | 头像图片;支持 image/png、image/jpeg、image/webp |
成功响应:
{
"avatar_url": "https://oss.example.com/avatars/user-1-v4.webp?X-Amz-Expires=86400&X-Amz-Signature=<signature>"
}
服务端会对上传内容做最终校验并转换为 WebP。上传接口同时承担新头像上传和旧头像替换;替换成功后,旧文件可以异步清理,但不能影响新 URL 在有效期内的可用性。
5.3 删除头像
DELETE /api/user/avatar
Authorization: Bearer <access_token>
成功响应:
{
"avatar_url": null
}
删除后,个人资料查询接口也必须返回 avatar_url: null。
6. 文件校验与存储要求
| 项目 | 要求 |
|---|---|
| 允许格式 | 客户端可上传 PNG、JPEG、WebP;服务端校验后统一转成 WebP。 |
| 格式安全 | 不得上传伪装格式、SVG 或动态图片;服务端应校验 MIME、文件头和实际解码结果。 |
| 大小限制 | 按服务端配置执行;超过限制时返回 HTTP 413 和 avatar_file_too_large。 |
| 图片内容 | 拒绝损坏图片、空文件、无法解码文件和伪装格式文件。 |
| 归属隔离 | 文件对象、数据库记录和访问 URL 均必须绑定当前用户。 |
| URL 处理 | OSS 环境返回 24 小时签名 URL;客户端不得持久化为永久地址,不得自行拼接或修改 URL。 |
| 隐私 | 头像属于用户资料,不应出现在公开作品、作品列表或未授权用户的接口响应中。 |
**客户端处理边界:**客户端目前会把图片处理为最长边 512px 的正方形,并可上传 PNG、JPEG 或 WebP;不要上传伪装格式、SVG 或动态图片。服务端仍需做最终校验并转换为 WebP。
7. 错误响应
| 场景 | HTTP 状态 | code |
说明 |
|---|---|---|---|
| 格式不支持 | 415 | avatar_unsupported_type |
仅允许 PNG/JPEG/WebP |
| 文件过大 | 413 | avatar_file_too_large |
超过服务端大小限制 |
| 图片损坏或无法解码 | 400 | avatar_invalid_file |
文件不是有效图片 |
| 上传失败 | 503 | avatar_storage_unavailable |
对象存储暂时不可用 |
错误响应示例:
{
"detail": {
"code": "avatar_file_too_large",
"message": "头像文件超过服务端大小限制"
}
}
8. 客户端调用时序
- 客户端启动或刷新资料时调用
GET /api/user/agent-profile,获取当前资料和新的avatar_url;不要复用已过期的签名 URL。 - 用户在个人资料弹窗中选择图片,客户端只生成本地预览,不请求服务端。
- 用户点击保存;如果是新头像,客户端先调用
POST /api/user/avatar;如果用户选择移除,则先调用DELETE /api/user/avatar。 - 头像上传或删除成功后,再调用现有 Agent Profile PUT 接口保存姓名、年龄、性别等资料。PUT 请求体不得包含
avatar_url。 - 如果后续资料 PUT 失败,重试时只重试资料 PUT,不要重复上传或删除已经成功的头像操作。
- 任一步失败,弹窗保持打开并展示错误;用户可以修正后重新保存。
**联调注意:**头像接口与个人资料 PUT 是两个独立请求。
avatar_url是只读响应字段,服务端不需要在个人资料 PUT 中处理该字段,也不需要客户端为头像 URL 增加版本号或自行处理签名参数。
9. 验收标准
- 登录用户可以通过
POST /api/user/avatar上传 PNG、JPEG 或 WebP,并获得可直接展示的avatar_url。 - 再次上传新图片可以替换旧头像;
GET /api/user/agent-profile返回最新avatar_url。 DELETE /api/user/avatar成功后,GET /api/user/agent-profile返回avatar_url: null。- 不同用户之间无法读取、覆盖或删除彼此的头像。
- 超过大小限制、格式不支持、图片损坏时返回明确且稳定的错误
code。 - 客户端启动或刷新资料时会重新获取
avatar_url;OSS 签名 URL 过期后不会继续复用旧 URL。 - 客户端不把
avatar_url放入 Agent Profile PUT 请求体,也不会自行拼接或修改 URL。 - 服务端最终将有效头像转换为 WebP;伪装格式、SVG、动态图片和损坏文件会被拒绝。
- 服务端异常不会返回包含内部存储路径、访问凭据或对象存储密钥的响应。
10. 联调检查清单
- 部署前已执行 Alembic 迁移
20260813_user_avatar_cloud_0040。 GET /api/user/agent-profile在有头像时返回 24 小时签名avatar_url,无头像时返回null。POST /api/user/avatar成功返回{ "avatar_url": "..." }。DELETE /api/user/avatar成功返回{ "avatar_url": null }。- Agent Profile PUT 请求体不接受、不处理
avatar_url。 - 错误码和 HTTP 状态码与本文档一致:415、413、400、503。
- 旧接口
/api/auth/me/avatar继续兼容,但新客户端不调用。
客户端已按上述接口契约完成接入;服务端接口上线后即可进行联调。