一、背景:上传功能不是“传上去就完事”
广告平台对上传素材要求高:
- 支持图片 / 视频 / ZIP(动画包)/ JSON 等格式
- 支持结构校验(如 ZIP 内必须包含特定文件)
- 分平台上传(管理后台、H5、小程序)行为一致
- 上传完成后需立即预览 + 可撤回
我从 0 设计并封装了整套上传系统,确保稳定、可控、可扩展。
二、整体架构图
+--------------------+ +-----------------+
| Upload 封装组件 | <---> | 校验逻辑模块 |
+--------------------+ +-----------------+
↓ ↓
预览渲染组件 文件结构分析器
↓ ↓
OSS 上传服务 安全检查(大小/格式)
三、上传组件封装
基础组件封装为 file-upload.vue:
<n-upload
:before-upload="handleBeforeUpload"
:custom-request="handleUpload"
/>
支持配置:文件类型、最大大小、是否必传、按钮文案、校验函数等
四、结构校验逻辑(以 ZIP 动效为例)
使用 JSZip 解压并校验内部结构:
import JSZip from 'jszip'
const validateZip = async (file: File) => {
const zip = await JSZip.loadAsync(file)
if (!zip.files['data.json'] || !zip.folder('images')) {
return { valid: false, reason: '缺少 data.json 或 images 文件夹' }
}
return { valid: true }
}
支持不同类型结构定义:
- Lottie:需包含
data.json+images/ - VAP:需包含
video.mp4+vapc.json - 公告包:任意 mp4/json,但需 1:1 匹配
五、OSS 上传 + 签名机制
上传统一走自定义 request + 后端签名:
const handleUpload = async ({ file }) => {
const { key, token } = await getUploadToken(file.name)
await ossClient.put(key, file)
return { fileUrl: `https://cdn.xxx.com/${key}` }
}
上传后回填 URL 并绑定预览图:
<n-image v-if="fileUrl" :src="fileUrl" width="160" />
六、安全策略设计
- 文件大小限制(组件 + 后端双层判断)
- 拒绝非法扩展名(仅允许白名单)
- 禁止执行脚本类内容(ZIP 内无 js/exe)
组件逻辑:
const beforeUpload = (file: File) => {
const isValidType = ['image/png', 'application/zip'].includes(file.type)
const isUnderSize = file.size < 5 * 1024 * 1024
return isValidType && isUnderSize
}
七、兼容性适配
- 管理后台:使用
n-upload+ OSS SDK - 小程序:使用
uni.chooseFile+uni.uploadFile - H5:原生
input[type=file]+ OSS + axios 流封装
抽象统一上传适配器:
const uploadAdapter = {
pc: uploadByOSS,
mp: uploadByMiniProgram,
h5: uploadByAxios
}[platform]
八、上线效果
- 平均上传成功率达 99.8%
- 结构错误拦截率 92%
- 多端上传行为一致,用户满意度明显提升
九、总结
上传体系的本质不是“上传成功”,而是“结构安全、用户明确、运维可控”。
我从文件类型规范、结构校验、上传流程、兼容适配、安全策略多维度出发,设计并实现了一个工程可落地的上传系统。