NovaStorage内部配置了多个存储后端(包括七牛云、阿里云OSS等),会随机选择存储后端,导致:
cloud-common bucket(失败,631错误)❌parseFile.save is not a function)❌根据文件大小智能选择存储策略,平衡可靠性和数据库空间
| 文件大小 | 存储方式 | 原因 |
|---|---|---|
| < 2MB | base64直接存储 | 快速、可靠、避免631错误 |
| ≥ 2MB | NovaStorage优先 | 节省数据库空间 |
| ≥ 2MB (失败) | base64降级存储 | 确保100%成功率 |
graph TD
A[文件上传] --> B{文件大小?}
B -->|< 2MB| C[base64存储]
B -->|≥ 2MB| D[尝试NovaStorage]
D -->|成功| E[云存储URL]
D -->|失败631| F[降级base64存储]
C --> G[100%成功]
E --> G
F --> G
const fileSizeMB = file.size / 1024 / 1024;
if (fileSizeMB < 2) {
// 小文件:直接base64(避免631)
const base64 = await this.fileToBase64(file);
uploadedFile = { url: `data:${file.type};base64,${base64}`, ... };
} else {
// 大文件:尝试NovaStorage
try {
const storage = await NovaStorage.withCid(cid);
uploadedFile = await storage.upload(file);
} catch (error) {
// 失败则降级到base64
const base64 = await this.fileToBase64(file);
uploadedFile = { url: `data:${file.type};base64,${base64}`, ... };
}
}
每天上传:50张图片
- 小图(<2MB):30张 × 1.5MB × 1.33 = 60MB (base64)
- 大图(≥2MB):20张 × 5MB = 100MB (云存储URL)
数据库增长:仅60MB/天 = 1.8GB/月 ✅ 可接受
每天上传:50张图片 × 平均3MB × 1.33 = 200MB/天
数据库增长:200MB/天 = 6GB/月 ⚠️ 需要定期清理
当前配置(v2.1优化版):
const USE_BASE64_THRESHOLD = 0.5; // ✅ 已优化为0.5MB
const MAX_FILE_SIZE_MB = 10; // ✅ 新增:拒绝超大文件
优化效果:
可根据实际情况调整:
// 如果数据库空间充足
const USE_BASE64_THRESHOLD = 1; // 1MB
// 如果数据库非常紧张
const USE_BASE64_THRESHOLD = 0.2; // 200KB
// 如果NovaStorage很稳定,不希望用base64
const USE_BASE64_THRESHOLD = 0; // 禁用base64,全部走云存储
createCleanedFile()避免特殊字符问题async uploadProjectFileWithRecord(...) {
// 重试机制
for (let attempt = 1; attempt <= 3; attempt++) {
try {
// 上传到NovaStorage
const storage = await NovaStorage.withCid(cid);
const uploadedFile = await storage.upload(cleanedFile, {...});
// 创建记录
const attachment = await this.saveToAttachmentTable(...);
const projectFile = await this.saveToProjectFile(...);
return projectFile;
} catch (error) {
// 🔥 检测631错误,自动切换到Parse File
if (error?.code === 631 && attempt === 1) {
const base64 = await this.fileToBase64(file);
const parseFile = new Parse.File(file.name, { base64 });
const savedFile = await parseFile.save();
// ... 使用Parse File URL创建记录
}
}
}
}
| 方法 | 原方案 | 新方案 | 状态 |
|---|---|---|---|
uploadCADFiles |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadAndAnalyzeImages |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadReferenceImageWithType |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadReferenceImage |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadFileWithRetry |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadCAD |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
| 方法 | 原方案 | 新方案 | 状态 |
|---|---|---|---|
confirmDragUpload |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
uploadDeliveryFile |
两步式 | uploadProjectFileWithRecord |
✅ 已修复 |
所有8个上传入口点已100%修复完成! ✨
// Step 1: 上传文件
const uploaded = await this.storage.upload(file, {
provider: 'oss', // ❌ 参数无效,仍会访问七牛云
onProgress: ...
});
// Step 2: 创建记录
const projectFile = await this.createProjectFileRecord(...);
// 一步完成,自动重试+fallback
const projectFileRecord = await this.projectFileService.uploadProjectFileWithRecord(
file,
projectId,
fileType,
spaceId,
stage,
{
imageType: 'other',
uploadTime: new Date(),
uploader: this.currentUser?.get('name')
},
(progress) => console.log(`进度: ${progress}%`)
);
// 直接使用返回的ProjectFile对象
const url = projectFileRecord.get('fileUrl');
const id = projectFileRecord.id;
1. 清除浏览器缓存
2. 连续上传20张图片
3. 观察:
✓ 不应该再出现七牛云API请求
✓ 所有图片100%成功上传
✓ 检测到631错误时自动切换到Parse File
4. 刷新页面验证持久化
📤 上传尝试 1/3: test.jpg
📦 使用存储桶CID: cDL6R1hgSi
📤 开始上传文件: test.jpg
✅ 文件上传成功: test.jpg
✅ [拖拽上传] 文件上传并记录创建成功: test.jpg
🔗 URL: https://file-cloud.fmode.cn/.../test.jpg
💾 ProjectFile ID: abc123xyz
📤 上传尝试 1/3: test.jpg
❌ 上传失败: 631 error
⚠️ 检测到631错误(no such bucket),尝试使用Parse File备用方案...
✅ Parse File备用方案成功
✅ 文件上传成功: test.jpg (通过Parse File)
provider: 'oss'参数(无效)projectFileService.uploadProjectFileWithRecord()一步完成