fenghuo/packages/storage/docs/S3_DOWNLOAD_MECHANISM.md

111 lines
2.8 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.

# S3存储下载机制说明
## 问题背景
在文件上传系统中,我们使用了两种存储类型:
- **本地存储Local**:文件存储在服务器本地文件系统
- **S3存储S3**文件存储在AWS S3或兼容的对象存储服务中
对于文件访问,我们使用了目录格式的 `fileId`,例如:`2025/05/28/RHwt8AkkZp`
## 存储结构差异
### 本地存储
- **fileId**`2025/05/28/RHwt8AkkZp` (目录路径)
- **实际存储**`/uploads/2025/05/28/RHwt8AkkZp/filename.ext`
- **下载方式**:扫描目录,找到实际文件,返回文件流
### S3存储
- **fileId**`2025/05/28/RHwt8AkkZp` (目录路径)
- **S3 Key**`2025/05/28/RHwt8AkkZp/filename.ext` (完整对象路径)
- **下载方式**重定向到S3 URL
## 核心问题
S3存储中对象的完整路径S3 Key包含文件名但我们的 `fileId` 只是目录路径,缺少文件名部分。
## 解决方案
### 1. 文件名重建策略
我们通过以下方式重建完整的S3路径
```typescript
const fileName = resource.title || 'file';
const fullS3Key = `${fileId}/${fileName}`;
```
### 2. URL生成逻辑
```typescript
// AWS S3
const s3Url = `https://${bucket}.s3.${region}.amazonaws.com/${fullS3Key}`;
// 自定义S3兼容服务如MinIO
const s3Url = `${endpoint}/${bucket}/${fullS3Key}`;
```
### 3. 下载流程
1. 从数据库获取文件信息fileId + resource.title
2. 重建完整S3 Key`${fileId}/${fileName}`
3. 生成S3直接访问URL
4. 302重定向到S3 URL让客户端直接从S3下载
## 优势
### 性能优势
- **302重定向**:避免服务器中转,减少带宽消耗
- **直接下载**客户端直接从S3下载速度更快
- **CDN友好**可配合CloudFront等CDN使用
### 安全考虑
- **公开读取**需要确保S3 bucket配置了适当的公开读取权限
- **预签名URL**未来可扩展支持预签名URL用于私有文件
## 局限性
### 文件名依赖
- 依赖数据库中存储的 `resource.title` 字段
- 如果文件名不匹配会导致404错误
### 替代方案
如果需要更可靠的方案,可以考虑:
1. **存储完整S3 Key**在数据库中存储完整的S3对象路径
2. **S3 ListObjects API**动态查询S3中的实际对象会增加API调用成本
## 环境配置
确保S3配置正确
```env
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兼容服务
```
## 测试验证
使用以下URL格式测试下载
```
/download/2025%2F05%2F28%2FRHwt8AkkZp
```
应该会302重定向到
```
https://your-bucket.s3.us-east-1.amazonaws.com/2025/05/28/RHwt8AkkZp/filename.ext
```