15 KiB
15 KiB
MinIO 文件存储接口文档
一、概述
本项目已集成 MinIO 对象存储,并在 Django 后端提供统一的文件存储 API。
MinIO 服务信息
| 项目 | 值 |
|---|---|
| API 地址 | http://127.0.0.1:9000 |
| Web 控制台 | http://127.0.0.1:9001 |
| 用户名 | admin |
| 密码 | zhengsl2026 |
| 默认 Bucket | ai-trainprediction |
Django 配置
MINIO_ENDPOINT = os.environ.get("MINIO_ENDPOINT", "127.0.0.1:9000")
MINIO_ACCESS_KEY = os.environ.get("MINIO_ACCESS_KEY", "admin")
MINIO_SECRET_KEY = os.environ.get("MINIO_SECRET_KEY", "zhengsl2026")
MINIO_SECURE = _env_bool("MINIO_SECURE", default=False)
MINIO_DEFAULT_BUCKET = os.environ.get("MINIO_DEFAULT_BUCKET", "ai-trainprediction")
MINIO_PRESIGN_EXPIRES = int(os.environ.get("MINIO_PRESIGN_EXPIRES", "3600"))
认证要求
所有 MinIO 接口均要求 JWT 认证:
Authorization: Bearer {access_token}
接口前缀
/server/minio/
二、接口总览
| 方法 | 路径 | 功能 |
|---|---|---|
| POST | /server/minio/bucket/create/ |
创建 Bucket |
| GET | /server/minio/bucket/list/ |
列出 Bucket |
| DELETE | /server/minio/bucket/delete/ |
删除 Bucket |
| POST | /server/minio/file/upload/ |
单文件上传 |
| POST | /server/minio/files/upload/ |
批量文件上传 |
| POST | /server/minio/file/upload-zip/ |
ZIP 解压后批量入库 |
| POST | /server/minio/file/upload-video-frames/ |
视频抽帧后图片入库 |
| POST | /server/minio/file/upload-base64/ |
Base64 文件上传 |
| GET | /server/minio/file/download/ |
流式下载文件 |
| GET | /server/minio/file/presign/ |
获取预签名下载 URL |
| GET | /server/minio/file/presign-upload/ |
获取预签名上传 URL |
| GET | /server/minio/file/preview/ |
流式预览文件 |
| GET | /server/minio/file/info/ |
获取文件元信息 |
| GET | /server/minio/files/ |
列出对象 |
| DELETE | /server/minio/file/delete/ |
删除单个文件 |
| DELETE | /server/minio/files/delete/ |
批量删除文件 |
| POST | /server/minio/file/copy/ |
复制文件 |
三、Bucket 管理
3.1 创建 Bucket
POST /server/minio/bucket/create/
Content-Type: application/json
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 否 | Bucket 名称,默认 ai-trainprediction |
成功响应:
{
"code": 200,
"data": {
"bucket_name": "my-bucket",
"created": true
},
"msg": "Bucket 创建成功"
}
说明:
- 若 Bucket 已存在,返回
created: false - MinIO 返回
BucketAlreadyExists/BucketAlreadyOwnedByYou时会转换为409
3.2 列出 Bucket
GET /server/minio/bucket/list/
成功响应:
{
"code": 200,
"data": ["ai-trainprediction", "my-bucket"],
"msg": "获取成功"
}
3.3 删除 Bucket
DELETE /server/minio/bucket/delete/
Content-Type: application/json
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 是 | Bucket 名称 |
成功响应:
{
"code": 200,
"data": {
"bucket_name": "my-bucket"
},
"msg": "Bucket 已删除"
}
错误说明:
404:Bucket 不存在409:Bucket 非空,无法删除
四、文件上传
4.1 单文件上传
POST /server/minio/file/upload/
Content-Type: multipart/form-data
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | 上传文件 |
bucket_name |
string | 否 | 目标 Bucket,默认 ai-trainprediction |
prefix |
string | 否 | 对象前缀,如 images/datasets |
object_name |
string | 否 | 指定对象名;不传则自动生成 |
自动命名规则:
{prefix}/YYYY-MM-DD/{uuid12}_{original_filename}
成功响应:
{
"code": 200,
"data": {
"bucket_name": "ai-trainprediction",
"object_name": "images/2026-07-01/a1b2c3d4e5f6_photo.jpg",
"original_name": "photo.jpg",
"size": 102400,
"content_type": "image/jpeg",
"presigned_url": "http://127.0.0.1:9000/..."
},
"msg": "上传成功"
}
说明:
- 该接口已改为流式上传,不会把整文件一次性读入内存
- 若
object_name明确指定且对象已存在,则会被覆盖
4.2 批量文件上传
POST /server/minio/files/upload/
Content-Type: multipart/form-data
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
files |
File[] | 是 | 多个文件 |
bucket_name |
string | 否 | 目标 Bucket |
prefix |
string | 否 | 对象前缀 |
成功响应:
{
"code": 200,
"data": [
{
"object_name": "images/2026-07-01/a1b2_photo1.jpg",
"original_name": "photo1.jpg",
"size": 102400,
"content_type": "image/jpeg",
"presigned_url": "http://127.0.0.1:9000/..."
}
],
"msg": "全部上传成功,共 1 个文件"
}
4.3 Base64 文件上传
POST /server/minio/file/upload-base64/
Content-Type: application/json
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
file_base64 |
string | 是 | Base64 编码内容 |
filename |
string | 是 | 原始文件名 |
bucket_name |
string | 否 | 目标 Bucket |
prefix |
string | 否 | 对象前缀 |
请求示例:
{
"file_base64": "/9j/4AAQSkZJRgABAQ...",
"filename": "avatar.png",
"bucket_name": "ai-trainprediction",
"prefix": "avatars"
}
成功响应:
{
"code": 200,
"data": {
"bucket_name": "ai-trainprediction",
"object_name": "avatars/2026-07-01/a1b2c3d4e5f6_avatar.png",
"original_name": "avatar.png",
"size": 51200,
"content_type": "image/png",
"presigned_url": "http://127.0.0.1:9000/..."
},
"msg": "上传成功"
}
说明:
- 此接口当前只支持
application/json - Base64 解码失败时返回
400
4.4 ZIP 解压批量入库
POST /server/minio/file/upload-zip/
Content-Type: multipart/form-data
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | ZIP 压缩包 |
bucket_name |
string | 否 | 目标 Bucket |
prefix |
string | 否 | MinIO 对象前缀 |
images_only |
bool | 否 | 是否仅入库图片文件,默认 false |
说明:
- 接口会自动解压 ZIP 内文件并逐个上传到 MinIO
- 默认保留 ZIP 内相对目录结构
- 会自动过滤目录项、隐藏文件和非法路径片段(如
..) images_only=true时,仅上传图片扩展名文件:jpg/jpeg/png/bmp/gif/webp/tif/tiff
成功响应:
{
"code": 200,
"data": {
"bucket_name": "ai-trainprediction",
"zip_name": "dataset.zip",
"uploaded_count": 2,
"uploaded": [
{
"source_name": "images/cat.jpg",
"object_name": "datasets/images/cat.jpg",
"size": 102400,
"content_type": "image/jpeg"
}
],
"skipped": ["docs/readme.txt"]
},
"msg": "ZIP 解压入库成功,共上传 2 个文件"
}
4.5 视频抽帧图片入库
POST /server/minio/file/upload-video-frames/
Content-Type: multipart/form-data
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
file |
File | 是 | 视频文件 |
bucket_name |
string | 否 | 目标 Bucket |
prefix |
string | 否 | MinIO 对象前缀 |
interval_seconds |
int | 否 | 抽帧时间间隔,单位秒,默认 1 |
start_second |
int | 否 | 开始抽帧时间,默认 0 |
end_second |
int | 否 | 结束抽帧时间,不传则到视频末尾 |
max_frames |
int | 否 | 最多生成图片数,默认 100 |
image_format |
string | 否 | 输出图片格式,支持 jpg/jpeg/png,默认 jpg |
说明:
- 当前支持的视频扩展名:
mp4/avi/mov/mkv/wmv/flv/mpeg/mpg/webm - 需要服务端安装
opencv-python - 抽出的图片会存入
{prefix}/{视频名}_frames/目录 - 文件名规则:
frame_00001_1200ms.jpg
成功响应:
{
"code": 200,
"data": {
"bucket_name": "ai-trainprediction",
"video_name": "demo.mp4",
"fps": 25.0,
"duration_seconds": 12.4,
"interval_seconds": 1,
"start_second": 0,
"end_second": 10,
"max_frames": 20,
"extracted_count": 10,
"extracted": [
{
"object_name": "videos/demo_frames/frame_00001_0ms.jpg",
"frame_index": 0,
"time_second": 0.0
}
]
},
"msg": "视频抽帧入库成功,共生成 10 张图片"
}
4.6 获取预签名上传 URL
GET /server/minio/file/presign-upload/?bucket_name={bucket}&object_name={object}&expires={seconds}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 否 | 目标 Bucket |
object_name |
string | 是 | 目标对象名 |
expires |
int | 否 | 有效期秒数,默认 3600,最大 604800 |
成功响应:
{
"code": 200,
"data": {
"presigned_url": "http://127.0.0.1:9000/ai-trainprediction/path/file.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...",
"expires_in": 3600
},
"msg": "获取成功"
}
五、文件下载与预览
5.1 流式下载文件
GET /server/minio/file/download/?bucket_name={bucket}&object_name={object}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 否 | Bucket 名称 |
object_name |
string | 是 | 对象名 |
说明:
- 返回流式响应,适合大文件下载
Content-Disposition为attachment
5.2 获取预签名下载 URL
GET /server/minio/file/presign/?bucket_name={bucket}&object_name={object}&expires={seconds}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 否 | Bucket 名称 |
object_name |
string | 是 | 对象名 |
expires |
int | 否 | 有效期秒数,默认 3600,最大 604800 |
成功响应:
{
"code": 200,
"data": {
"presigned_url": "http://127.0.0.1:9000/ai-trainprediction/path/file.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...",
"expires_in": 3600
},
"msg": "获取成功"
}
说明:
expires <= 0时返回400- 超过 7 天会被自动截断为
604800
5.3 流式预览文件
GET /server/minio/file/preview/?bucket_name={bucket}&object_name={object}
说明:
- 返回流式响应
Content-Disposition为inline- 适合图片、PDF、文本等浏览器可直接预览的文件
六、文件管理
6.1 获取文件元信息
GET /server/minio/file/info/?bucket_name={bucket}&object_name={object}
成功响应:
{
"code": 200,
"data": {
"name": "images/2026-07-01/a1b2_photo.jpg",
"size": 102400,
"etag": "d41d8cd98f00b204e9800998ecf8427e",
"content_type": "image/jpeg",
"last_modified": "2026-07-01T12:00:00+00:00",
"presigned_url": "http://127.0.0.1:9000/..."
},
"msg": "获取成功"
}
6.2 列出对象
GET /server/minio/files/?bucket_name={bucket}&prefix={prefix}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
bucket_name |
string | 否 | Bucket 名称 |
prefix |
string | 否 | 仅列出指定前缀下的对象 |
成功响应:
{
"code": 200,
"data": [
{
"name": "images/2026-07-01/a1b2_photo.jpg",
"size": 102400,
"last_modified": "2026-07-01T12:00:00+00:00",
"etag": "d41d8cd98f00b204e9800998ecf8427e",
"content_type": "image/jpeg",
"is_dir": false
}
],
"msg": "共 1 个对象"
}
6.3 删除单个文件
DELETE /server/minio/file/delete/
Content-Type: application/json
请求体:
{
"bucket_name": "ai-trainprediction",
"object_name": "images/2026-07-01/a1b2_photo.jpg"
}
成功响应:
{
"code": 200,
"data": {
"object_name": "images/2026-07-01/a1b2_photo.jpg"
},
"msg": "删除成功"
}
6.4 批量删除文件
DELETE /server/minio/files/delete/
Content-Type: application/json
请求体:
{
"bucket_name": "ai-trainprediction",
"object_names": [
"images/photo1.jpg",
"images/photo2.png"
]
}
成功响应:
{
"code": 200,
"data": {
"deleted": 2
},
"msg": "全部删除成功"
}
部分成功响应:
{
"code": 207,
"data": {
"deleted": 1,
"errors": ["images/photo2.png"]
},
"msg": "部分删除,1 个失败"
}
6.5 复制文件
POST /server/minio/file/copy/
Content-Type: application/json
请求体:
{
"src_bucket": "ai-trainprediction",
"src_object": "images/photo.jpg",
"dst_bucket": "ai-trainprediction",
"dst_object": "backup/photo.jpg"
}
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
src_bucket |
string | 否 | 源 Bucket,默认 ai-trainprediction |
src_object |
string | 是 | 源对象名 |
dst_bucket |
string | 否 | 目标 Bucket,默认 ai-trainprediction |
dst_object |
string | 是 | 目标对象名 |
成功响应:
{
"code": 200,
"data": {
"object_name": "backup/photo.jpg"
},
"msg": "复制成功"
}
说明:
- 若目标 Bucket 不存在,接口会自动创建
七、错误码说明
| HTTP 状态码 | 含义 |
|---|---|
200 |
成功 |
207 |
批量删除部分成功 |
400 |
参数错误、expires 不合法、Base64 解码失败等 |
401 |
未携带或携带了无效 JWT Token |
403 |
MinIO 拒绝访问 |
404 |
Bucket 或对象不存在 |
409 |
Bucket 已存在、Bucket 非空等冲突 |
500 |
其他 MinIO / 服务端错误 |
错误响应格式:
{
"code": 409,
"msg": "Bucket 非空,无法删除",
"detail": "S3 operation failed; code: BucketNotEmpty, ..."
}
八、代码结构
backend/
├── config/settings/base.py
├── config/api_urls.py
└── apps/common/
├── minio_client.py
└── views/minio_storage.py
minio_client.py
封装的核心方法包括:
| 方法 | 功能 |
|---|---|
bucket_exists() |
检查 Bucket 是否存在 |
create_bucket() |
创建 Bucket |
list_buckets() |
列出 Bucket |
remove_bucket() |
删除空 Bucket |
upload_file() |
上传本地文件 |
upload_bytes() |
上传字节数据 |
upload_stream() |
流式上传文件对象 |
download_file() |
下载到本地 |
download_bytes() |
下载为 bytes |
get_object() |
获取对象流响应 |
get_object_info() |
获取对象元信息 |
object_exists() |
判断对象是否存在 |
list_objects() |
列出对象 |
delete_object() |
删除单个对象 |
delete_objects() |
批量删除对象 |
presign_get() |
获取预签名下载 URL |
presign_upload() |
获取预签名上传 URL |
generate_object_name() |
生成唯一对象名 |
copy_object() |
复制对象 |
九、注意事项
- 所有接口均要求 JWT 认证
- 下载和预览接口已经改为流式响应,适合较大文件
upload-base64当前只支持application/json- ZIP 入库默认保留压缩包中的相对目录结构,并会过滤非法路径
- 视频抽帧依赖
opencv-python expires必须大于 0,最大有效期为 7 天- 指定
object_name时可能覆盖已有对象,请谨慎使用 - 删除 Bucket 前必须先清空其中所有对象