model_train_dm/MinIO文件存储接口文档.md
2026-07-27 17:51:49 +08:00

710 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 配置
```python
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 认证:
```http
Authorization: Bearer {access_token}
```
### 接口前缀
```text
/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
```http
POST /server/minio/bucket/create/
Content-Type: application/json
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bucket_name` | string | 否 | Bucket 名称,默认 `ai-trainprediction` |
成功响应:
```json
{
"code": 200,
"data": {
"bucket_name": "my-bucket",
"created": true
},
"msg": "Bucket 创建成功"
}
```
说明:
- 若 Bucket 已存在,返回 `created: false`
- MinIO 返回 `BucketAlreadyExists` / `BucketAlreadyOwnedByYou` 时会转换为 `409`
### 3.2 列出 Bucket
```http
GET /server/minio/bucket/list/
```
成功响应:
```json
{
"code": 200,
"data": ["ai-trainprediction", "my-bucket"],
"msg": "获取成功"
}
```
### 3.3 删除 Bucket
```http
DELETE /server/minio/bucket/delete/
Content-Type: application/json
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bucket_name` | string | 是 | Bucket 名称 |
成功响应:
```json
{
"code": 200,
"data": {
"bucket_name": "my-bucket"
},
"msg": "Bucket 已删除"
}
```
错误说明:
- `404`Bucket 不存在
- `409`Bucket 非空,无法删除
---
## 四、文件上传
### 4.1 单文件上传
```http
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 | 否 | 指定对象名;不传则自动生成 |
自动命名规则:
```text
{prefix}/YYYY-MM-DD/{uuid12}_{original_filename}
```
成功响应:
```json
{
"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 批量文件上传
```http
POST /server/minio/files/upload/
Content-Type: multipart/form-data
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `files` | File[] | 是 | 多个文件 |
| `bucket_name` | string | 否 | 目标 Bucket |
| `prefix` | string | 否 | 对象前缀 |
成功响应:
```json
{
"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 文件上传
```http
POST /server/minio/file/upload-base64/
Content-Type: application/json
```
请求体:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `file_base64` | string | 是 | Base64 编码内容 |
| `filename` | string | 是 | 原始文件名 |
| `bucket_name` | string | 否 | 目标 Bucket |
| `prefix` | string | 否 | 对象前缀 |
请求示例:
```json
{
"file_base64": "/9j/4AAQSkZJRgABAQ...",
"filename": "avatar.png",
"bucket_name": "ai-trainprediction",
"prefix": "avatars"
}
```
成功响应:
```json
{
"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 解压批量入库
```http
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`
成功响应:
```json
{
"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 视频抽帧图片入库
```http
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`
成功响应:
```json
{
"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
```http
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` |
成功响应:
```json
{
"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 流式下载文件
```http
GET /server/minio/file/download/?bucket_name={bucket}&object_name={object}
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bucket_name` | string | 否 | Bucket 名称 |
| `object_name` | string | 是 | 对象名 |
说明:
- 返回流式响应,适合大文件下载
- `Content-Disposition``attachment`
### 5.2 获取预签名下载 URL
```http
GET /server/minio/file/presign/?bucket_name={bucket}&object_name={object}&expires={seconds}
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bucket_name` | string | 否 | Bucket 名称 |
| `object_name` | string | 是 | 对象名 |
| `expires` | int | 否 | 有效期秒数,默认 `3600`,最大 `604800` |
成功响应:
```json
{
"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 流式预览文件
```http
GET /server/minio/file/preview/?bucket_name={bucket}&object_name={object}
```
说明:
- 返回流式响应
- `Content-Disposition``inline`
- 适合图片、PDF、文本等浏览器可直接预览的文件
---
## 六、文件管理
### 6.1 获取文件元信息
```http
GET /server/minio/file/info/?bucket_name={bucket}&object_name={object}
```
成功响应:
```json
{
"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 列出对象
```http
GET /server/minio/files/?bucket_name={bucket}&prefix={prefix}
```
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `bucket_name` | string | 否 | Bucket 名称 |
| `prefix` | string | 否 | 仅列出指定前缀下的对象 |
成功响应:
```json
{
"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 删除单个文件
```http
DELETE /server/minio/file/delete/
Content-Type: application/json
```
请求体:
```json
{
"bucket_name": "ai-trainprediction",
"object_name": "images/2026-07-01/a1b2_photo.jpg"
}
```
成功响应:
```json
{
"code": 200,
"data": {
"object_name": "images/2026-07-01/a1b2_photo.jpg"
},
"msg": "删除成功"
}
```
### 6.4 批量删除文件
```http
DELETE /server/minio/files/delete/
Content-Type: application/json
```
请求体:
```json
{
"bucket_name": "ai-trainprediction",
"object_names": [
"images/photo1.jpg",
"images/photo2.png"
]
}
```
成功响应:
```json
{
"code": 200,
"data": {
"deleted": 2
},
"msg": "全部删除成功"
}
```
部分成功响应:
```json
{
"code": 207,
"data": {
"deleted": 1,
"errors": ["images/photo2.png"]
},
"msg": "部分删除1 个失败"
}
```
### 6.5 复制文件
```http
POST /server/minio/file/copy/
Content-Type: application/json
```
请求体:
```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 | 是 | 目标对象名 |
成功响应:
```json
{
"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 / 服务端错误 |
错误响应格式:
```json
{
"code": 409,
"msg": "Bucket 非空,无法删除",
"detail": "S3 operation failed; code: BucketNotEmpty, ..."
}
```
---
## 八、代码结构
```text
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()` | 复制对象 |
---
## 九、注意事项
1. 所有接口均要求 JWT 认证
2. 下载和预览接口已经改为流式响应,适合较大文件
3. `upload-base64` 当前只支持 `application/json`
4. ZIP 入库默认保留压缩包中的相对目录结构,并会过滤非法路径
5. 视频抽帧依赖 `opencv-python`
6. `expires` 必须大于 0最大有效期为 7 天
7. 指定 `object_name` 时可能覆盖已有对象,请谨慎使用
8. 删除 Bucket 前必须先清空其中所有对象