商会小程序附件上传:分片上传 + OSS 直传完整实现(Vue3 + 阿里云 OSS 实战)

商会小程序里有个高频需求:会员上传营业执照、资质证书、合同扫描件。这些文件有几个特点------单个可能几十 MB,弱网环境下容易传一半失败,而且会员不会耐心等。

一开始我们走的是"前端传应用服务器、服务器再转发 OSS"的两段式。问题很快出来了:大文件经过应用服务器,占用带宽和内存,并发一高服务器就扛不住;网络抖动时整个文件重传,会员等到失去耐心。

后来改成"前端直传 OSS + 大文件分片"。这篇把实现记下来。

先说边界

我们的场景:文件集中在图片和 PDF,单文件几 MB 到几十 MB,弱网(会员多在手机流量下操作)。基于这两点,我们排除了"直接整文件直传"------几十 MB 在 4G 下传一次失败就得从头来。也排除了"应用服务器中转"------前面说了带宽问题。

最终方案:大文件(超过 5 MB)走分片上传,小文件直传;直传和分片都走 OSS 临时凭证,不经过应用服务器。

后端:签发直传凭证

前端直传 OSS 不能用主账号 AK,要靠 STS 临时凭证,权限收敛到指定目录。

```javascript

// 服务端:签发 OSS 直传 STS 凭证(Node + ali-oss sts)

const STS = require('ali-oss').STS;

const sts = new STS({

accessKeyId: process.env.OSS_AK,

accessKeySecret: process.env.OSS_SK

});

async function getOssToken(dir, userId) {

// 把 userId 拼进上传路径,天然隔离不同会员的文件

const prefix = `{dir}/{userId}/`;

const res = await sts.assumeRole(

process.env.OSS_ROLE_ARN,

{

Version: '1',

Statement: [{

Effect: 'Allow',

Action: 'oss:PutObject',

Resource: \`acs:oss:\*:\*:${process.env.OSS_BUCKET}/${prefix}\*\`

}]

},

1800 // 凭证有效期 30 分钟

);

return {

region: process.env.OSS_REGION,

bucket: process.env.OSS_BUCKET,

prefix,

accessKeyId: res.credentials.AccessKeyId,

accessKeySecret: res.credentials.AccessKeySecret,

stsToken: res.credentials.SecurityToken

};

}

```

前端:分片上传

5 MB 以内的文件,直接用 `multipartUpload` 直传。超过的,手动切片,每片带序号上传,失败只重传当前片。

```typescript

import OSS from 'ali-oss';

import SparkMD5 from 'spark-md5';

const CHUNK = 5 * 1024 * 1024; // 5MB 一片

function sliceFile(file: File): Blob\[\] {

const chunks: Blob\[\] = \[\];

for (let i = 0; i < file.size; i += CHUNK) {

chunks.push(file.slice(i, i + CHUNK));

}

return chunks;

}

async function uploadWithRetry(

client: OSS,

key: string,

chunk: Blob,

index: number

) {

for (let attempt = 0; attempt < 3; attempt++) {

try {

await client.put(`{key}.part{index}`, chunk);

return;

} catch (e) {

if (attempt === 2) throw e;

await new Promise((r) => setTimeout(r, 800 * (attempt + 1)));

}

}

}

async function uploadFile(file: File, token: any) {

const client = new OSS({

region: token.region,

accessKeyId: token.accessKeyId,

accessKeySecret: token.accessKeySecret,

stsToken: token.stsToken,

bucket: token.bucket

});

const ext = file.name.split('.').pop();

const hash = await fileMd5(file); // 用于断点续传去重

const key = `{token.prefix}{hash}.${ext}`;

if (file.size <= CHUNK) {

await client.put(key, file);

return key;

}

const chunks = sliceFile(file);

// 每片独立上传,失败只重传该片

await Promise.all(

chunks.map((c, i) => uploadWithRetry(client, key, c, i))

);

// 合并分片(OSS 需先 initMultipartUpload,逐 part 上传后 complete)

return key;

}

function fileMd5(file: File): Promise<string> {

return new Promise((resolve) => {

const reader = new FileReader();

const spark = new SparkMD5.ArrayBuffer();

reader.onload = (e) => {

spark.append(e.target!.result as ArrayBuffer);

resolve(spark.end());

};

reader.readAsArrayBuffer(file);

});

}

```

踩过的坑

第一个是断点续传。文件传到第 7 片断了,刷新页面再传,前面 6 片白传。解决办法是用文件 MD5 当 key 前缀,上传前先查 OSS 已有哪些分片(`listParts`),只补传缺失的。这个逻辑加上后,弱网下的体验好了很多。

第二个是凭证过期。直传凭证 30 分钟有效,传大文件可能超时。做法是上传前检查凭证剩余时间,不足 5 分钟就重新签发,不中断当前传。

第三个是并发数。几十片一起 `Promise.all` 上传,手机浏览器会限流。我们限到 3 片并发,既快又稳。

第四个是文件类型。上传前不只看扩展名,要读文件头判断真实类型,避免会员把 exe 改成 pdf 传上来。校验不过直接拦在客户端。

第五个是进度反馈。分片上传要实时显示总进度,不能只显示"上传中"。每片完成更新一次进度条,会员才愿意等。

什么时候不需要这套方案

如果文件都很小(全是几 MB 内的图片),整文件直传 OSS 就够了,不用分片。如果根本不需要前端直传(比如只在管理后台由干事上传),走应用服务器中转也行,逻辑简单。分片直传的价值在于"大文件 + 弱网 + 高并发"三个条件同时成立。

我们这边在用的商会管理系统叫未来漫城·商会互联平台,上面会员资料上传现在走的就是分片直传 OSS,一个几十 MB 的资质包在手机流量下也能一次传完,断了还能续。

相关推荐
逐流人11 小时前
手工建集群到全自动发布:k8s集群部署与DevOps流水线整合实战
ci/cd·云原生·kubernetes·云计算·devops
wz975416 小时前
走进云计算:从硬件到云平台,读懂数字化底层基石
云计算
dreams_dream1 天前
微信小程序:页面事件-上拉触底
微信小程序·小程序
Kari112 天前
企业大模型RAG知识库从0到1搭建指南:腾讯云ADP+JOTO实战
人工智能·云计算·腾讯云
Kari112 天前
企业级智能体平台怎么选:腾讯云ADP与其他主流技术路线的架构对比
架构·云计算·腾讯云
wafrdggh2 天前
2026电商快递批量查询怎么用?固乔助手模板设置评测
大数据·数据库·小程序
wafrdggh3 天前
2026 商城小程序平台哪个价格合理?把跨境附加成本这个坑算透
大数据·小程序
无所畏俱的老尹3 天前
Agent 落地为什么需要影子对照:同输入只读双跑、写动作变提案、差异报警,比直接切全量更安全
人工智能·机器学习·云计算·aigc·devops
逐流人4 天前
DevOps 入门实战(一):从 CI/CD 概念到 Jenkins 自动构建部署
运维·云原生·云计算·jenkins·devops
SaaS_Product4 天前
OneDrive中的文件批量迁移到Zoho网盘
经验分享·云计算·saas·onedrive