192 lines
4.4 KiB
Markdown
192 lines
4.4 KiB
Markdown
# 上传大小限制说明
|
||
|
||
## 📊 当前配置
|
||
|
||
### 1. Next.js 服务器限制
|
||
**位置:** `next.config.js`
|
||
```javascript
|
||
experimental: {
|
||
serverActions: {
|
||
bodySizeLimit: '100mb' // ✅ 当前限制:100MB
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 前端验证
|
||
**位置:** `components/UploadModal.tsx`
|
||
- ❌ **当前没有文件大小验证**
|
||
- ✅ 有文件类型验证(图片和ZIP)
|
||
- ✅ 显示文件大小
|
||
|
||
### 3. 其他可能的限制
|
||
|
||
#### Docker 容器
|
||
- ✅ 无特殊限制
|
||
|
||
#### 反向代理(如果使用)
|
||
- ⚠️ **需要注意:** 如果使用Nginx反向代理,默认限制是1MB
|
||
- 需要配置:`client_max_body_size 100m;`
|
||
|
||
#### FRP内网穿透
|
||
- ✅ FRP默认无大小限制
|
||
|
||
---
|
||
|
||
## 🔧 建议优化
|
||
|
||
### 1. 添加前端文件大小验证
|
||
|
||
在 `components/UploadModal.tsx` 中添加验证:
|
||
|
||
\`\`\`typescript
|
||
const MAX_PREVIEW_SIZE = 10 * 1024 * 1024; // 10MB
|
||
const MAX_ZIP_SIZE = 100 * 1024 * 1024; // 100MB
|
||
|
||
const handlePreviewChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
const file = e.target.files?.[0]
|
||
if (file) {
|
||
if (!file.type.startsWith('image/')) {
|
||
setError('请选择图片文件')
|
||
return
|
||
}
|
||
|
||
// 添加大小验证
|
||
if (file.size > MAX_PREVIEW_SIZE) {
|
||
setError('预览图片不能超过10MB')
|
||
return
|
||
}
|
||
|
||
setPreviewImage(file)
|
||
setPreviewUrl(URL.createObjectURL(file))
|
||
setError('')
|
||
}
|
||
}
|
||
|
||
const handleZipChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
const file = e.target.files?.[0]
|
||
if (file) {
|
||
if (!file.name.endsWith('.zip') && !file.name.endsWith('.rar')) {
|
||
setError('请选择压缩包文件(.zip 或 .rar)')
|
||
return
|
||
}
|
||
|
||
// 添加大小验证
|
||
if (file.size > MAX_ZIP_SIZE) {
|
||
setError(\`压缩包不能超过\${MAX_ZIP_SIZE / 1024 / 1024}MB\`)
|
||
return
|
||
}
|
||
|
||
setZipFile(file)
|
||
setError('')
|
||
}
|
||
}
|
||
\`\`\`
|
||
|
||
### 2. 添加上传进度显示
|
||
|
||
\`\`\`typescript
|
||
const [uploadProgress, setUploadProgress] = useState(0)
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault()
|
||
setError('')
|
||
|
||
// ... 验证代码 ...
|
||
|
||
setUploading(true)
|
||
|
||
try {
|
||
const formData = new FormData()
|
||
formData.append('previewImage', previewImage)
|
||
formData.append('zipFile', zipFile)
|
||
formData.append('productModel', productModel)
|
||
formData.append('sceneName', sceneName)
|
||
|
||
const xhr = new XMLHttpRequest()
|
||
|
||
xhr.upload.addEventListener('progress', (e) => {
|
||
if (e.lengthComputable) {
|
||
const percentComplete = Math.round((e.loaded / e.total) * 100)
|
||
setUploadProgress(percentComplete)
|
||
}
|
||
})
|
||
|
||
xhr.addEventListener('load', () => {
|
||
if (xhr.status === 201) {
|
||
onSuccess()
|
||
onClose()
|
||
} else {
|
||
const data = JSON.parse(xhr.responseText)
|
||
setError(data.error || '上传失败')
|
||
}
|
||
setUploading(false)
|
||
})
|
||
|
||
xhr.addEventListener('error', () => {
|
||
setError('上传失败,请稍后重试')
|
||
setUploading(false)
|
||
})
|
||
|
||
xhr.open('POST', '/api/materials/upload')
|
||
xhr.send(formData)
|
||
|
||
} catch (error) {
|
||
console.error('Upload error:', error)
|
||
setError('上传失败,请稍后重试')
|
||
setUploading(false)
|
||
}
|
||
}
|
||
\`\`\`
|
||
|
||
### 3. 如果需要增加限制到更大
|
||
|
||
修改 `next.config.js`:
|
||
\`\`\`javascript
|
||
experimental: {
|
||
serverActions: {
|
||
bodySizeLimit: '500mb' // 增加到500MB
|
||
}
|
||
}
|
||
\`\`\`
|
||
|
||
---
|
||
|
||
## 📋 测试清单
|
||
|
||
- [ ] 测试上传小于10MB的预览图
|
||
- [ ] 测试上传10MB的预览图(应该成功)
|
||
- [ ] 测试上传大于10MB的预览图(应该被拒绝)
|
||
- [ ] 测试上传小于100MB的ZIP文件
|
||
- [ ] 测试上传100MB的ZIP文件(应该成功)
|
||
- [ ] 测试上传大于100MB的ZIP文件(应该被拒绝)
|
||
- [ ] 测试网络中断后重新上传
|
||
- [ ] 测试上传进度显示
|
||
|
||
---
|
||
|
||
## 🚨 注意事项
|
||
|
||
1. **网络超时**
|
||
- 大文件上传可能需要较长时间
|
||
- 建议设置合理的超时时间
|
||
- 考虑添加断点续传功能
|
||
|
||
2. **存储空间**
|
||
- NAS存储空间:`/mnt/tank/apps/youyidian-3d/uploads`
|
||
- 定期清理不需要的文件
|
||
- 监控磁盘使用情况
|
||
|
||
3. **S3存储**
|
||
- 预览图片存储在S3,有足够空间
|
||
- 注意S3的流量费用
|
||
|
||
4. **用户体验**
|
||
- 添加文件大小提示
|
||
- 显示上传进度
|
||
- 提供清晰的错误信息
|
||
|
||
---
|
||
|
||
**最后更新:** 2025-10-16
|
||
**当前限制:** 预览图无限制(建议10MB),ZIP文件100MB
|