文章目录
前言
本文是我在实际项目中实现微信小程序直传阿里云 OSS 的完整方案总结,涵盖从权限配置到上传逻辑封装,再到上传优化与秒传处理,意在快速构建高性能、可维护的文件上传能力,也帮助后来者少走弯路。
一、为什么要使用直传 OSS?
传统小程序上传图片/视频的方式,往往是:
小程序 ➝ 后端中转 ➝ 阿里云 OSS
这种方式存在三大问题:
• 上传慢:服务端中转造成延迟
• 成本高:中转占带宽、占存储
• 不稳定:服务端并发压力大时更容易失败
直传方案优势明显:
优势 | 说明 |
---|---|
较低宽带成本 | 文件直接由用户上传至OSS,无需服务端中转 |
提升上传速度 | 小程序原生uploadfile支持高效直传 |
提升安全性 | 使用STS临时授权,避免泄露秘钥 |
灵活扩展 | 可支持秒传、预签名、CDN访问等优化法案 |
二、整体架构与实现思路
用户选择文件
↓
调用后端签名接口获取 OSS V4 签名凭证
↓
使用 wx.uploadFile 将文件直传到 OSS
↓
上传成功后提交文件元信息给后端(如 hash、path、fileSize、时间戳等)
↓
服务端记录文件并处理 ACL、转码、CDN 等
三、阿里云 OSS 配置(V4 签名)
签名方式采用 OSS 推荐的 OSS4-HMAC-SHA256 方式,配合临时 STS Token 生成策略。
1. 权限设置
• Bucket 必须启用 STS 签名上传权限
• 设置为 私有(防止默认公开)
• 开通 STS,创建角色绑定策略:
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"oss:PutObject",
"oss:PostObject"
],
"Resource": "acs:oss:*:*:your-bucket-name/*"
}
],
"Version": "1"
}
2. 后端生成签名参数(返回给小程序)
// 示例返回结构
{
policy: 'base64-policy',
signature: 'v4-hmac-sha256',
credential: 'STS.xxx/yyyy/region/oss/aliyun_v4_request',
date: '20250425T123456Z',
security_token: 'token...',
file_base_path: 'userId/familyId/album/...',
signature_version: 'OSS4-HMAC-SHA256'
}
四、微信小程序端上传流程(功能模块拆解与封装)
第一步:调用签名接口获取上传凭证
封装为 getOssUploadPolicy.ts
const getOssUploadPolicy = async (): Promise<OssUploadConfig> => {
const familyId = wx.getStorageSync("familiess")?.[0]?.name;
const albumPath = wx.getStorageSync("albumUploadTarget")?.path;
const res = await wx.requestAPI({
method: "GET",
url: "/families/oss/signature",
data: { family_id: familyId, file_path: albumPath },
});
return res.data;
};
第二步:封装 uploadFilesToOSS
export const uploadFilesToOSS = async (files: FileWithHash[]) => {
const urls: string[] = [];
const metaList: any[] = [];
const ossConfig = await getOssUploadPolicy();
const userId = wx.getStorageSync("userInfo").id;
for (const [index, file] of files.entries()) {
const filename = `${Date.now()}_${index}.${getExt(file.path)}`;
const fileKey = `${ossConfig.file_base_path}/${filename}`;
const formData = {
key: fileKey,
policy: ossConfig.policy,
"x-oss-signature-version": ossConfig.signature_version,
"x-oss-credential": ossConfig.credential,
"x-oss-date": ossConfig.date,
"x-oss-signature": ossConfig.signature,
"x-oss-security-token": ossConfig.security_token,
success_action_status: "200"
};
await new Promise((resolve, reject) => {
wx.uploadFile({
url: "https://your-bucket.oss-cn-region.aliyuncs.com",
filePath: file.path,
name: "file",
formData,
success: (res) => {
if (res.statusCode === 200) {
urls.push(`${OSS_HOST}/${fileKey}`);
metaList.push({
album_id: albumId,
family_id: familyId,
file_name: filename,
file_path: fileKey,
object_key: file.hash,
creator_uid: userId,
file_type: file.type,
file_size: file.sizeKb,
upload_time: file.time,
hash_value: file.hash,
});
resolve();
} else reject();
},
fail: reject,
});
});
}
await wx.requestAPI({
method: "POST",
url: "/photos",
data: { data: metaList },
});
return urls;
};
五、上传优化:多文件 + 秒传机制
文件秒传流程
1. 获取所有文件的 MD5 哈希(推荐使用 spark-md5)
2. 调用服务端 hash/check 接口,传入哈希数组
3. 过滤掉已上传的 hash,执行上传
4. 已上传的只需提交元信息(不重复上传)
多文件封装支持选择来源:
• chooseMessageFile //文件更多类型 支持选择微信群组文件
• chooseMedia // 支持拍摄
并统一格式为:
{
path: string;
name: string;
size: number;
sizeKb: number;
time: number;
type: "image" | "video";
hash: string;
}
六、常见问题与坑位合集
问题 | 原因 | 解决方式 |
---|---|---|
上传 403 | 签名不匹配 | 检查 credential 与 policy |
图片 hash 重复 | 上传时间精度不足 | 增加 index + 毫秒后缀 |
file.name 为空 | chooseMedia 不返回 | 动构造文件名 |
上传成功无法访问 | OSS 默认私有 | 上传成功后调用接口公开文件或设置 ACL |
多选图片顺序错乱 | 异步上传未 await | 严格按顺序 await 或封装 Promise.allSettled() |
七、总结与建议
• 建议封装上传为模块化组件,调用清晰、可复用
• 建议所有上传统一使用 V4 签名,兼容性更强
• 上传前的哈希、过滤、重命名要严格规范
• 上传成功后应尽快提交元信息并设置访问策略
• 可扩展预签名下载、防盗链、临时授权访问等高级功能
附:目录结构推荐
/utils/
├── getOssUploadPolicy.ts
├── uploadFilesToOSS.ts
├── computeHash.ts
├── fileFilter.ts
/pages/
└── albumUploader/
├── index.ts
├── index.wxml
├── index.scss
结语
这篇文章是我在实际项目中从 0 到 1 完整落地「微信小程序直传阿里云 OSS」的全过程。
如果你也在做类似需求,希望这篇文章能给你一些思路与实践参考。
欢迎点赞、转发或收藏,有问题评论区见,我们一起进步。