fenghuo/apps/backend/src/upload/README.md

233 lines
7.3 KiB
Markdown
Raw 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.

# 上传模块架构改造
本模块已从 NestJS 架构成功改造为 Hono + Bun 架构,并支持多种存储后端的无感切换。
## 文件结构
```
src/upload/
├── tus.ts # TUS 协议服务核心实现
├── upload.index.ts # 资源管理相关函数
├── upload.rest.ts # Hono REST API 路由
├── storage.adapter.ts # 存储适配器系统 🆕
├── storage.utils.ts # 存储工具类 🆕
├── scheduler.ts # 定时清理任务
├── utils.ts # 工具函数
├── types.ts # 类型定义
└── README.md # 本文档
```
## 存储适配器系统
### 支持的存储类型
1. **本地存储 (Local)** - 文件存储在本地文件系统
2. **S3 存储 (S3)** - 文件存储在 AWS S3 或兼容的对象存储服务
### 环境变量配置
#### 本地存储配置
```bash
STORAGE_TYPE=local
UPLOAD_DIR=./uploads
UPLOAD_EXPIRATION_MS=0 # 0 表示不自动过期(推荐设置)
```
#### S3 存储配置
```bash
STORAGE_TYPE=s3
S3_BUCKET=your-bucket-name
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
S3_ENDPOINT=https://s3.amazonaws.com # 可选,支持其他 S3 兼容服务
S3_FORCE_PATH_STYLE=false # 可选,路径风格
S3_PART_SIZE=8388608 # 可选,分片大小 (8MB)
S3_MAX_CONCURRENT_UPLOADS=60 # 可选,最大并发上传数
UPLOAD_EXPIRATION_MS=0 # 0 表示不自动过期(推荐设置)
```
### 存储类型记录
- **数据库支持**: 每个资源记录都包含 `storageType` 字段,标识文件使用的存储后端
- **自动记录**: 上传时自动记录当前的存储类型
- **迁移支持**: 支持批量更新现有资源的存储类型标记
### 不过期设置
- **默认行为**: 过期时间默认设为 0表示文件不会自动过期
- **手动清理**: 提供多种手动清理选项
- **灵活控制**: 可根据需要设置过期时间,或完全禁用自动清理
### 无感切换机制
1. **单例模式管理**: `StorageManager` 使用单例模式确保全局一致性
2. **自动配置检测**: 启动时根据环境变量自动选择存储类型
3. **统一接口**: 所有存储类型都实现相同的 TUS `DataStore` 接口
4. **运行时切换**: 支持运行时切换存储配置(需要重启生效)
## API 端点
### 资源管理
- `GET /api/upload/resource/:fileId` - 获取文件资源信息
- `GET /api/upload/resources` - 获取所有资源
- `GET /api/upload/resources/storage/:storageType` - 🆕 根据存储类型获取资源
- `GET /api/upload/resources/status/:status` - 🆕 根据状态获取资源
- `GET /api/upload/resources/uploading` - 🆕 获取正在上传的资源
- `GET /api/upload/stats` - 🆕 获取资源统计信息
- `DELETE /api/upload/resource/:id` - 删除资源
- `PATCH /api/upload/resource/:id` - 更新资源
- `POST /api/upload/cleanup` - 手动触发清理
- `POST /api/upload/cleanup/by-status` - 🆕 根据状态清理资源
- `POST /api/upload/migrate-storage` - 🆕 迁移资源存储类型标记
### 存储管理
- `GET /api/upload/storage/info` - 获取当前存储配置信息
- `POST /api/upload/storage/switch` - 切换存储类型
- `POST /api/upload/storage/validate` - 验证存储配置
### TUS 协议
- `OPTIONS /api/upload/*` - TUS 协议选项请求
- `HEAD /api/upload/*` - TUS 协议头部请求
- `POST /api/upload/*` - TUS 协议创建上传
- `PATCH /api/upload/*` - TUS 协议上传数据
- `GET /api/upload/*` - TUS 协议获取状态
## 新增 API 使用示例
### 获取存储类型统计
```javascript
const response = await fetch('/api/upload/stats');
const stats = await response.json();
// {
// total: 150,
// byStatus: { "UPLOADED": 120, "UPLOADING": 5, "PROCESSED": 25 },
// byStorageType: { "local": 80, "s3": 70 }
// }
```
### 查询特定存储类型的资源
```javascript
const response = await fetch('/api/upload/resources/storage/s3');
const s3Resources = await response.json();
```
### 迁移存储类型标记
```javascript
const response = await fetch('/api/upload/migrate-storage', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ from: 'local', to: 's3' }),
});
// { success: true, message: "Migrated 50 resources from local to s3", count: 50 }
```
### 手动清理特定状态的资源
```javascript
const response = await fetch('/api/upload/cleanup/by-status', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
status: 'UPLOADING',
olderThanDays: 7,
}),
});
```
## 🆕 存储管理示例
### 获取存储信息
```javascript
const response = await fetch('/api/upload/storage/info');
const storageInfo = await response.json();
// { type: 'local', config: { directory: './uploads' } }
```
### 切换到 S3 存储
```javascript
const newConfig = {
type: 's3',
s3: {
bucket: 'my-bucket',
region: 'us-west-2',
accessKeyId: 'YOUR_ACCESS_KEY',
secretAccessKey: 'YOUR_SECRET_KEY',
},
};
const response = await fetch('/api/upload/storage/switch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newConfig),
});
```
### 验证存储配置
```javascript
const response = await fetch('/api/upload/storage/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newConfig),
});
const validation = await response.json();
// { valid: true, message: 'Storage configuration is valid' }
```
## 特性保留
1. **TUS 协议支持** - 完全保留原有的断点续传功能
2. **文件命名** - 保留安全的文件命名策略
3. **资源状态管理** - 保留完整的上传状态跟踪
4. **自动清理** - 保留过期文件清理功能(默认禁用)
5. **数据库集成** - 保留 Prisma ORM 数据库操作
## 🆕 新增特性
1. **多存储后端支持** - 支持本地存储和 S3 存储
2. **无感切换** - 运行时可切换存储类型
3. **配置验证** - 提供存储配置验证功能
4. **存储信息查询** - 可查询当前存储配置
5. **统一日志** - 存储操作统一日志记录
6. **🆕 存储类型记录** - 数据库记录每个资源的存储类型
7. **🆕 灵活清理** - 支持按状态、时间等条件清理
8. **🆕 统计分析** - 提供详细的资源统计信息
9. **🆕 不过期设置** - 默认不自动过期,避免意外删除
## 运行
服务启动时会自动:
1. 根据环境变量初始化存储适配器
2. 初始化 TUS 服务器
3. 注册 REST API 路由
4. 启动定时清理任务(如果启用)
支持的存储切换场景:
- 开发环境使用本地存储
- 生产环境使用 S3 存储
- 混合云部署灵活切换
- 存储迁移时批量更新资源标记
## 💡 最佳实践
1. **过期设置**: 推荐设置 `UPLOAD_EXPIRATION_MS=0` 避免文件意外过期
2. **存储记录**: 利用数据库中的 `storageType` 字段追踪文件位置
3. **定期清理**: 使用手动清理 API 定期清理不需要的资源
4. **监控统计**: 使用统计 API 监控存储使用情况
5. **迁移策略**: 在存储迁移时先更新环境变量,再使用迁移 API 更新数据库标记
无需代码修改,仅通过环境变量即可实现存储后端的无感切换。