图片、视频等资源存放
目标
本文档说明当前代码中已经实现的头像、图片、视频资源处理规则。
当前实现分为两类:
- 用户头像:注册时直接传
avatar_base64,服务端校验后保存到users.avatar_url - 聊天资源:图片、视频通过上传接口保存到
static目录,并返回/api/static/...访问地址
代码落点
- 注册接口:
controllers/auth_controller.go - 用户创建:
models/user_model.go - 头像 base64 校验:
models/resource_model.go - 资源上传接口:
controllers/resource_controller.go - 资源保存规则:
models/resource_model.go - 路由注册:
routers/router.go - 静态资源暴露:
main.go
数据库要求
头像 base64 可能超过 255 字符,因此 users.avatar_url 必须使用 LONGTEXT。
sql
ALTER TABLE users MODIFY avatar_url LONGTEXT NULL;当前本地数据库已按以上规则调整。
用户头像
注册接口
text
POST /api/auth/register请求类型:
text
application/json请求体:
json
{
"username": "alice",
"password": "123456",
"nickname": "Alice",
"avatar_base64": "data:image/png;base64,iVBORw0KGgo="
}字段说明:
username:必填,本地登录账号password:必填,本地登录密码nickname:选填,不传时默认使用usernameavatar_base64:选填,头像 base64 字符串;解码后的图片大小不能超过 10 MiB
avatar_base64 支持两种格式:
text
iVBORw0KGgo=text
data:image/png;base64,iVBORw0KGgo=服务端处理规则:
- 为空时不保存头像,
users.avatar_url写入NULL - 不为空时会校验 base64 是否可解码
- 解码后的头像原始内容不能超过 10 MiB
- 支持标准 base64 和 raw base64
- 如果传入 data URL,服务端校验逗号后面的 base64 内容
- 数据库存储原始传入字符串,方便前端直接展示
成功响应中的用户信息仍使用 avatar_url 字段:
json
{
"code": 200,
"data": {
"user": {
"id": 1,
"username": "alice",
"nickname": "Alice",
"avatar_url": "data:image/png;base64,iVBORw0KGgo=",
"auth_source": "local",
"status": 1
},
"token": "<jwt-token>"
},
"message": "注册成功"
}常见错误:
400:参数校验失败400:头像 base64 不合法413:头像大小超过 10 MiB,或注册请求体过大409:用户名已存在500:服务器内部错误
图片和视频上传
上传接口
text
POST /api/resources/upload请求要求:
- 需要登录
- 请求头携带
Authorization: Bearer <token> - 请求类型为
multipart/form-data - 单次上传请求体最大 100 MiB
- 服务端同时校验扩展名白名单和图片/视频常见格式文件头,扩展名与内容不匹配时拒绝上传
表单字段:
file:必填,上传文件type:必填,资源类型,只支持image或video
保存路径
图片保存到:
text
static/images/{user_id}/{timestamp}.{ext}视频保存到:
text
static/videos/{user_id}/{timestamp}.{ext}说明:
{user_id}来自当前登录用户 ID{timestamp}当前实现使用纳秒级时间戳{ext}来自原始文件名后缀,并统一转为小写- 返回 URL 使用
/api/static/... main.go已通过engine.Static("/api/static", "./static")暴露静态资源
示例:
text
static/images/1/1780000000000000000.png
static/videos/1/1780000000000000000.mp4对应访问地址:
text
/api/static/images/1/1780000000000000000.png
/api/static/videos/1/1780000000000000000.mp4支持后缀
图片:
.jpg.jpeg.png.gif.webp
视频:
.mp4.mov.webm
当前实现按文件后缀校验,不做内容 MIME 嗅探。
curl 示例
上传图片:
bash
curl -X POST "http://127.0.0.1:8080/api/resources/upload" \
-H "Authorization: Bearer <jwt-token>" \
-F "type=image" \
-F "file=@/path/to/demo.png"上传视频:
bash
curl -X POST "http://127.0.0.1:8080/api/resources/upload" \
-H "Authorization: Bearer <jwt-token>" \
-F "type=video" \
-F "file=@/path/to/demo.mp4"成功响应
图片响应示例:
json
{
"code": 200,
"data": {
"type": "image",
"url": "/api/static/images/1/1780000000000000000.png"
},
"message": "上传资源成功"
}视频响应示例:
json
{
"code": 200,
"data": {
"type": "video",
"url": "/api/static/videos/1/1780000000000000000.mp4"
},
"message": "上传资源成功"
}常见错误
400:未上传file400:type不是image或video400:文件没有后缀400:文件后缀不在白名单中401:未登录或登录已失效500:创建目录、创建文件或保存文件失败
和消息接口的关系
资源上传接口只负责保存文件并返回 URL,不会自动发送消息。
客户端发送图片或视频消息时,推荐流程:
- 调用
POST /api/resources/upload上传图片或视频 - 拿到响应中的
url - 调用消息发送接口,把
url写入消息content
图片消息示例:
json
{
"conversation_id": 1,
"client_msg_id": "client-image-001",
"message_type": "image",
"content": {
"url": "/api/static/images/1/1780000000000000000.png"
}
}视频消息当前可以先按文件类资源发送,后续如需独立 video 消息类型,需要扩展 messages.message_type 枚举和消息内容校验规则。
当前边界
- 当前不生成缩略图
- 当前不压缩图片或视频
- 当前不做 MIME 内容嗅探
- 当前不做对象存储上传
- 当前不记录资源表
- 当前消息接口不会自动清理
static下的资源文件 - 当前同名风险通过纳秒级时间戳降低,不额外生成随机后缀