文件上传 API 文档

概述

本系统提供三种类型的文件上传接口,分别用于不同的使用场景:

接口适用场景文件大小限制特点
upload_image图片上传1KB - 50MB自动压缩生成多尺寸
upload_video视频上传1KB - 50MB保留原始文件
upload_file小文件直传1KB - 2GB简单直接
upload_file_template_url + upload_file_success大文件上传无限制预签名URL,客户端直传S3

1. 上传图片 POST /upload_image

使用场景

  • 用户头像、封面图片
  • 聊天中发送的图片
  • 服务/作品展示图片
  • 任何需要多尺寸缩略图的图片场景

请求参数

参数类型必填说明
filefile图片文件
scenestring使用场景标识,��认 default

文件限制

  • 支持格式:jpg, png, jpeg, gif, webp
  • 文件大小:1KB - 50MB

响应示例

{
  "data": {
    "id": 123,
    "url_og": "https://storage.example.com/upload_images/user_1/chat/2024-01-15/abc123_og.jpg",
    "url_sm": "https://storage.example.com/upload_images/user_1/chat/2024-01-15/abc123_sm.webp",
    "url_md": "https://storage.example.com/upload_images/user_1/chat/2024-01-15/abc123_md.webp",
    "url_lg": "https://storage.example.com/upload_images/user_1/chat/2024-01-15/abc123_lg.webp",
    "width": 1920,
    "height": 1080,
    "mime": "image/jpeg",
    "size": 1048576
  }
}

响应字段说明

字段类型说明
idint上传图片记录ID
url_ogstring原始图片URL
url_smstring小尺寸缩略图URL (320px宽)
url_mdstring中尺寸缩略图URL (650px宽)
url_lgstring大尺寸缩略图URL (1250px宽)
widthint图片宽度(压缩完成后更新)
heightint图片高度(压缩完成后更新)
mimestringMIME类型
sizeint文件大小(字节)

图片压缩逻辑

上传完成后,系统会异步执行图片压缩任务(CompressImage Job):

  1. 压缩尺寸

    • sm: 320px 宽度
    • md: 650px 宽度
    • lg: 1250px 宽度
  2. 输出格式:统一转换为 webp 格式

  3. 压缩工具

    • 静态图片:优先使用 cwebp,失败时降级到 ImageMagick
    • 动态图片(GIF):使用 ImageMagick 缩放 + gif2webp 转换
  4. 压缩质量:80%

  5. 处理超时:30分钟

删除逻辑

调用 UploadService::deleteUploadImage($uploadImageId) 时:

  1. 软删除数据库记录
  2. 异步删除存储中的所有相关文件(原图 + 3个压缩版本)

2. 上传视频 POST /upload_video

使用场景

  • 聊天中发送的短视频
  • 服务/作品展示视频
  • 任何需要视频预览的场景

请求参数

参数类型必填说明
filefile视频文件
scenestring使用场景标识,默认 default

文件限制

  • 支持格式:mp4
  • 文件大小:1KB - 50MB

响应示例

{
  "data": {
    "id": 456,
    "url_sm": "https://storage.example.com/upload_videos/user_1/chat/2024-01-15/def456_og.mp4",
    "url_md": "https://storage.example.com/upload_videos/user_1/chat/2024-01-15/def456_og.mp4",
    "url_lg": "https://storage.example.com/upload_videos/user_1/chat/2024-01-15/def456_og.mp4",
    "mime": "video/mp4",
    "size": 10485760
  }
}

响应字段说明

字段类型说明
idint上传视频记录ID
url_smstring小尺寸视频URL(当前与原始相同)
url_mdstring中尺寸视频URL(当前与原始相同)
url_lgstring大尺寸视频URL(当前与原始相同)
mimestringMIME类型
sizeint文件大小(字节)

压缩逻辑

当前视频上传不进行压缩处理url_smurl_mdurl_lg 均指向原始文件。

删除逻辑

调用 UploadService::deleteUploadVideo($uploadVideoId) 时:

  1. 软删除数据库记录
  2. 异步删除存储中的所有相关文件

3. 上传文件(直传) POST /upload_file

使用场景

  • 小于 2GB 的普通文件上传
  • 不需要预签名URL的简单场景
  • 服务器带宽充足时的快速上传

请求参数

参数类型必填说明
filefile任意文件
scenestring使用场景标识,默认 default

文件限制

  • 支持格式:所有格式
  • 文件大小:1KB - 2GB

响应示例

{
  "data": {
    "id": 789,
    "name": "document.pdf",
    "url_og": "https://storage.example.com/upload_files/user_1/chat/2024-01-15/ghi789_og.pdf",
    "mime": "application/pdf",
    "size": 2097152,
    "state": "successed",
    "expired_at": "2024-04-15T00:00:00.000000Z"
  }
}

响应字段说明

字段类型说明
idint上传文件记录ID
namestring原始文件名
url_ogstring文件URL
mimestringMIME类型
sizeint文件大小(字节)
statestring状态:successed
expired_atstring/null过期时间(仅 scene=chat 时有值)

4. 上传文件(预签名URL)

适用于大文件上传,分两步完成:

4.1 获取预签名URL POST /upload_file_template_url

使用场景

  • 大文件上传(超过服务器上传限制)
  • 需要客户端直传到 S3/OSS 的场景
  • 减轻服务器带宽压力

请求参数

参数类型必填说明
namestring文件名(含扩展名)
scenestring使用场景标识,默认 default

响应示例

{
  "data": {
    "upload_file_id": 1001,
    "file_path": "upload_files/user_1/chat/2024-01-15/xyz123_og.zip",
    "url": "https://s3.amazonaws.com/bucket/upload_files/user_1/chat/2024-01-15/xyz123_og.zip?X-Amz-Algorithm=...",
    "headers": {
      "Content-Type": "application/octet-stream"
    }
  }
}

响应字段说明

字段类型说明
upload_file_idint上传文件记录ID,用于后续确认
file_pathstring文件存储路径
urlstring预签名上传URL(有效期1小时)
headersobject上传时需要携带的请求头

4.2 确认上传成功 POST /upload_file_success

客户端使用预签名URL上传完成后,调用此接口确认。

请求参数

参数类型必填说明
idintupload_file_template_url 返回的 upload_file_id

响应示例

{
  "data": {
    "id": 1001,
    "name": "large_file.zip",
    "url_og": "https://storage.example.com/upload_files/user_1/chat/2024-01-15/xyz123_og.zip",
    "mime": "application/zip",
    "size": 1073741824,
    "state": "successed",
    "expired_at": "2024-04-15T00:00:00.000000Z"
  }
}

错误响应

{
  "message": "File Not Found"
}

状态码:400(文件未在存储中找到)


5. 文件状态说明

UploadFile 模型的 state 字段:

状态说明
Pendingpending等待上传(预签名URL已生成,文件未上传)
Successedsuccessed上传成功
Deleteddeleted已删除(定时任务清理后的状态)

6. 定时任务清理说明

清理规则

系统每天执行 DeleteExpiredUploadFile 定时任务,清理过期的聊天文件:

清理条件

  • scene = 'chat'(仅清理聊天场景的文件)
  • state != 'deleted'(未被删除的文件)
  • created_at < 当前时间 - 3个月(创建时间超过3个月)

清理操作

  1. 从存储中删除物理文件
  2. 将数据库记录的 state 更新为 deleted

过期时间计算

对于 scene = 'chat' 的文件,expired_at 字段会自动计算:

  • 如果数据库中有 expired_at 值,直接使用
  • 否则,基于 created_at + 3个月计算

其他场景的文件 expired_atnull,不会被自动清理。

执行时间

定时任务在 routes/console.php 中配置,每天执行一次:

Schedule::command(DeleteExpiredUploadFile::class)->daily();

7. 接口使用区别总结

特性upload_imageupload_videoupload_fileupload_file_template_url
上传方式服务器中转服务器中转服务器中转客户端直传S3
文件大小≤50MB≤50MB≤2GB无限制
自动压缩✅ 生成3种尺寸
适用文件图片视频任意任意
调用次数1次1次1次2次
服务器压力高(压缩)高(大文件)

选择建议

  1. 图片文件 → 使用 upload_image,自动获得多尺寸缩略图
  2. 视频文件 → 使用 upload_video
  3. 小文件(<50MB) → 使用 upload_file,简单直接
  4. 大文件(>50MB) → 使用 upload_file_template_url + upload_file_success,减轻服务器压力
  5. 聊天附件 → 设置 scene=chat,系统会在3个月后自动清理

8. 存储路径规则

所有上传文件按以下规则组织:

{top_folder}/user_{user_id}/{scene}/{date}/{unique_id}_{suffix}.{extension}
  • top_folder: upload_images / upload_videos / upload_files
  • user_id: 上传用户ID
  • scene: 使用场景标识
  • date: 上传日期 (YYYY-MM-DD)
  • unique_id: 唯一标识符 (uniqid)
  • suffix: og(原始) / sm(小) / md(中) / lg(大)