微信小程序直传阿里云 OSS 的实践总结做小程序图片上传时最容易踩坑的不是选图 UI而是鉴权、签名、实际上传、回调收尾这一整条链路。下面整理一套在生产环境跑通过的做法接口路径和业务字段已做脱敏重点讲流程和容易翻车的地方。整体思路小程序端不持有AccessKey也不自己算 OSS 签名。正确姿势是前端选文件、算 MD5、组装元信息调自家后端「上传鉴权」接口拿到 OSS 上传凭证根据后端返回的上传方式走表单上传 / 预签名 PUT / 分片 PUTOSS 上传成功后再调后端「完成上传」接口拿到可读 URL 和 fileId这样密钥只在服务端小程序只拿临时 policy、signature 或预签名 URL。选图 → 算 MD5 → 鉴权接口 → 直传 OSS → 完成上传接口 → 回写业务表单第一步选文件与本地预处理选图用wx.chooseImage注意count要扣掉已选数量别让用户超上限。wx.chooseImage({count:remainCount,sizeType:[compressed],sourceType:[album,camera],success(res){// 把 tempFiles 转成内部 fileList 结构}});本地文件建议单独标记isLocal: true和已上传的远程图分开管理避免重复上传。算 MD5上传前先调wx.getFileInfodigestAlgorithm设为md5wx.getFileInfo({filePath,digestAlgorithm:md5,success(res){constfileMd5res.digest;}});MD5 有两个用处传给后端做秒传 / 去重后端若发现文件已存在可直接返回成功不用再传 OSS拼进文件名降低重名概率生成 OSS 对象名别直接用微信临时路径当文件名。常见做法{业务前缀}_{md5前12位}_{时间戳}_{三位随机数}.{后缀}后缀从原路径截取MIME 类型也按后缀推断jpg/png/gif/webp。第二步调鉴权接口鉴权请求体大致包含这些字段字段名按你们后端约定来字段说明bucket_pre公有/私有桶标识如 public / privatefile_dirOSS 目录如weixin/imagesfile_name上一步生成的对象名file_md5文件 MD5file_size字节大小typeMIME如 image/jpegpart_size / chunk_count分片相关小图通常 chunk_count1鉴权响应里重点关注字段含义upload_status上传状态码决定是否还要传 OSSserver_type存储类型值为 oss 时走 OSS 直传file_pathOSS 对象 keyfile_id业务文件 ID收尾接口要用host / bucket / region拼 OSS 上传域名policy / signature / access_id表单上传凭证V1security_tokenSTS 临时凭证chunk_urls分片预签名 URL 列表upload_status 的快速路径生产里后端常会返回这几种状态数字仅作示例以你们接口为准已存在、待收尾文件在 OSS 有了前端跳过直传直接调「完成上传」完全秒传连收尾都省了直接返回 read_path / file_id这两种情况能省不少流量和时间前端一定要判别无脑再传一遍。第三步实际上传 OSS后端返回type oss时按优先级依次尝试方式一表单 POST推荐小文件首选条件host file_path policy signature accessKeyId齐全且不是 OSS V4 签名。用wx.uploadFile不要用wx.requestwx.uploadFile({url:https://{bucket}.{region}.aliyuncs.com,filePath:tempPath,name:file,formData:{key:file_path,OSSAccessKeyId:access_id,policy:policy,signature:signature,success_action_status:200,x-oss-security-token:security_token// STS 场景必传},timeout:30000});成功状态码一般是200 或 204。uploadFile自带进度回调UI 好做。V4 签名字段不同formData 要换成key policy x-oss-signature-version x-oss-credential x-oss-date x-oss-signature x-oss-security-token如有 success_action_statusV4 和 V1 不能混用字段判错了一直 403。方式二预签名 PUT鉴权接口直接给了带signature/x-oss-signature/security-token的 URL 时用 PUT 整文件上传constfswx.getFileSystemManager();fs.readFile({filePath:tempPath,success(readRes){wx.request({url:presignedPutUrl,method:PUT,data:readRes.data,header:{Content-Type:image/jpeg,x-oss-security-token:security_token// URL 里没带 token 时才加 header}});}});注意PUT 要先readFile读进内存大图会占内存图片场景一般还能接受视频就要考虑分片Content-Type要和签名时一致否则验签失败域名必须是https方式三二次要签名鉴权响应里没有完整 policy但有file_path再调一次「获取签名」接口拿到 policy/signature 后仍走表单上传。这是兜底路径别把它当主流程否则多一次 RTT。方式四分片 PUT非 OSS 或后端自建分片server_type不是 oss或返回了chunk_urls数组时按分片顺序 PUTfs.readFile({filePath,position:start,length:chunkSize,success(readRes){wx.request({url:chunkItem.upload_url,method:PUT,data:readRes.data,header:{Content-Type:application/octet-stream}});}});分片大小常见 15MB按file_size / chunk_size算片数顺序上传每片成功再传下一片最后调完成接口。第四步完成上传OSS 返回 200/204 只代表对象进去了业务库里的文件记录通常还没落。必须再调「完成上传」接口把 file_id、md5、路径等传回去拿到read_path/url前端展示、表单提交用file_id业务关联用view_path有时和 read_path 不同CDN、鉴权访问等漏掉这一步后台看不到文件表单提交也会缺 fileId。小程序侧必配项1. 服务器域名白名单微信公众平台 → 开发 → 开发管理 → 开发设置 → 服务器域名uploadFile 合法域名OSS 的 bucket 域名如https://xxx.oss-cn-hangzhou.aliyuncs.comrequest 合法域名自家 API 域名 若用 PUT 直传 OSSOSS 域名也要加域名不对的表现uploadFile:fail url not in domain list不是代码 bug。2. 只用 HTTPSOSS 和小程序都要求 HTTPS代码里把http://统一替换成https://。3. 超时单文件上传建议设 30s 超时超时后标记失败、允许重试别一直 loading。容易踩的坑1. 用 wx.request 模拟 multipart 表单表单上传请用wx.uploadFile。自己拼 multipart body 在微信里又麻烦又容易错 boundary。2. V1 / V4 签名混用鉴权响应里如果出现x-oss-signature-version且含 OSS4就不能再走OSSAccessKeyId policy signature那套 V1 formData。3. STS 漏传 token临时凭证场景x-oss-security-token表单字段或 PUT header缺了必 403。预签名 URL 里已带 token 就别重复加 header。4. Content-Type 不一致PUT 上传时 header 里的类型必须和签名时一致jpg 就传image/jpeg别默认 octet-stream分片除外。5. 大文件 readFile 爆内存整文件 PUT 会把文件读进内存。图片压缩后一般 OK大视频要分片或走后端中转。6. 只传 OSS 不调完成接口对象在桶里有了业务系统没记录等于白传。7. 文件名 / key 重复纯时间戳命名高并发会撞名。MD5 随机数能缓解最终仍以 OSS 返回为准。8. 进度条假死uploadFile有onProgressUpdatePUT 分片要自己按已传字节算百分比。9. 秒传逻辑没接后端都返回「文件已存在」了前端还在传 OSS浪费用户流量和时间。组件层的一些实用细节如果封装成上传组件这几件事值得做本地 / 远程分状态isLocal标记待传文件已有fileId的跳过外部值同步加锁value/netImgs/netFileIds多个 prop 互相触发 observer 时用isSyncing防循环 setData批量顺序上传for...await一张一张传比并发更稳OSS 和小程序连接数都有限统一 emit上传完抛changeurls fileIds和uploadComplete表单页只关心结果失败可重试失败把uploading置 false、progress归零别卡在半成功状态后端需要配合什么前端能跑通后端至少提供三个能力鉴权根据 md5/大小/目录生成 OSS key返回上传凭证或秒传结果签名可选V4 或动态 policy 时单独签发完成上传OSS 对象落库返回可读地址和 fileId密钥、RAM 角色、STS 有效期、bucket 策略都在服务端配别下发到小程序。最小可用流程伪代码asyncfunctionuploadOne(tempPath,meta){constmd5awaitgetFileMd5(tempPath);constfileNamebuildFileName(tempPath,md5);constauthawaitapi.post(/upload/auth,{file_md5:md5,file_name:fileName,file_size:meta.size,file_dir:wx_app/images,type:meta.mime});if(auth.upload_statusINSTANT){returnauth;// 秒传}if(auth.server_typeoss){if(hasFormPolicy(auth)){awaitossFormUpload(tempPath,auth);}elseif(hasPresignedUrl(auth)){awaitossPutUpload(tempPath,auth);}else{constsignawaitapi.post(/upload/sign,{file_path:auth.file_path});awaitossFormUpload(tempPath,{...auth,...sign});}}else{awaitchunkPutUpload(tempPath,auth.chunk_urls);}returnapi.post(/upload/finish,{file_id:auth.file_id,file_md5:md5});}小结微信小程序传 OSS核心就一句话后端签发、前端直传、完成后回调。选型上小图优先wx.uploadFile表单 POST有预签名 URL 再用 PUT大文件走分片。上线前把 OSS 域名加进白名单、STS token 传对、完成接口接上这三件做到位大部分 403 和「传了但保存不了」的问题都能避开。如果你也在做类似组件建议先把鉴权响应打日志脱敏后看清楚后端到底走哪条分支再写上传逻辑比一上来硬套官方 demo 省时间得多。
微信小程序文件,图片直传阿里云 OSS 的最佳实践
发布时间:2026/5/26 7:48:38
微信小程序直传阿里云 OSS 的实践总结做小程序图片上传时最容易踩坑的不是选图 UI而是鉴权、签名、实际上传、回调收尾这一整条链路。下面整理一套在生产环境跑通过的做法接口路径和业务字段已做脱敏重点讲流程和容易翻车的地方。整体思路小程序端不持有AccessKey也不自己算 OSS 签名。正确姿势是前端选文件、算 MD5、组装元信息调自家后端「上传鉴权」接口拿到 OSS 上传凭证根据后端返回的上传方式走表单上传 / 预签名 PUT / 分片 PUTOSS 上传成功后再调后端「完成上传」接口拿到可读 URL 和 fileId这样密钥只在服务端小程序只拿临时 policy、signature 或预签名 URL。选图 → 算 MD5 → 鉴权接口 → 直传 OSS → 完成上传接口 → 回写业务表单第一步选文件与本地预处理选图用wx.chooseImage注意count要扣掉已选数量别让用户超上限。wx.chooseImage({count:remainCount,sizeType:[compressed],sourceType:[album,camera],success(res){// 把 tempFiles 转成内部 fileList 结构}});本地文件建议单独标记isLocal: true和已上传的远程图分开管理避免重复上传。算 MD5上传前先调wx.getFileInfodigestAlgorithm设为md5wx.getFileInfo({filePath,digestAlgorithm:md5,success(res){constfileMd5res.digest;}});MD5 有两个用处传给后端做秒传 / 去重后端若发现文件已存在可直接返回成功不用再传 OSS拼进文件名降低重名概率生成 OSS 对象名别直接用微信临时路径当文件名。常见做法{业务前缀}_{md5前12位}_{时间戳}_{三位随机数}.{后缀}后缀从原路径截取MIME 类型也按后缀推断jpg/png/gif/webp。第二步调鉴权接口鉴权请求体大致包含这些字段字段名按你们后端约定来字段说明bucket_pre公有/私有桶标识如 public / privatefile_dirOSS 目录如weixin/imagesfile_name上一步生成的对象名file_md5文件 MD5file_size字节大小typeMIME如 image/jpegpart_size / chunk_count分片相关小图通常 chunk_count1鉴权响应里重点关注字段含义upload_status上传状态码决定是否还要传 OSSserver_type存储类型值为 oss 时走 OSS 直传file_pathOSS 对象 keyfile_id业务文件 ID收尾接口要用host / bucket / region拼 OSS 上传域名policy / signature / access_id表单上传凭证V1security_tokenSTS 临时凭证chunk_urls分片预签名 URL 列表upload_status 的快速路径生产里后端常会返回这几种状态数字仅作示例以你们接口为准已存在、待收尾文件在 OSS 有了前端跳过直传直接调「完成上传」完全秒传连收尾都省了直接返回 read_path / file_id这两种情况能省不少流量和时间前端一定要判别无脑再传一遍。第三步实际上传 OSS后端返回type oss时按优先级依次尝试方式一表单 POST推荐小文件首选条件host file_path policy signature accessKeyId齐全且不是 OSS V4 签名。用wx.uploadFile不要用wx.requestwx.uploadFile({url:https://{bucket}.{region}.aliyuncs.com,filePath:tempPath,name:file,formData:{key:file_path,OSSAccessKeyId:access_id,policy:policy,signature:signature,success_action_status:200,x-oss-security-token:security_token// STS 场景必传},timeout:30000});成功状态码一般是200 或 204。uploadFile自带进度回调UI 好做。V4 签名字段不同formData 要换成key policy x-oss-signature-version x-oss-credential x-oss-date x-oss-signature x-oss-security-token如有 success_action_statusV4 和 V1 不能混用字段判错了一直 403。方式二预签名 PUT鉴权接口直接给了带signature/x-oss-signature/security-token的 URL 时用 PUT 整文件上传constfswx.getFileSystemManager();fs.readFile({filePath:tempPath,success(readRes){wx.request({url:presignedPutUrl,method:PUT,data:readRes.data,header:{Content-Type:image/jpeg,x-oss-security-token:security_token// URL 里没带 token 时才加 header}});}});注意PUT 要先readFile读进内存大图会占内存图片场景一般还能接受视频就要考虑分片Content-Type要和签名时一致否则验签失败域名必须是https方式三二次要签名鉴权响应里没有完整 policy但有file_path再调一次「获取签名」接口拿到 policy/signature 后仍走表单上传。这是兜底路径别把它当主流程否则多一次 RTT。方式四分片 PUT非 OSS 或后端自建分片server_type不是 oss或返回了chunk_urls数组时按分片顺序 PUTfs.readFile({filePath,position:start,length:chunkSize,success(readRes){wx.request({url:chunkItem.upload_url,method:PUT,data:readRes.data,header:{Content-Type:application/octet-stream}});}});分片大小常见 15MB按file_size / chunk_size算片数顺序上传每片成功再传下一片最后调完成接口。第四步完成上传OSS 返回 200/204 只代表对象进去了业务库里的文件记录通常还没落。必须再调「完成上传」接口把 file_id、md5、路径等传回去拿到read_path/url前端展示、表单提交用file_id业务关联用view_path有时和 read_path 不同CDN、鉴权访问等漏掉这一步后台看不到文件表单提交也会缺 fileId。小程序侧必配项1. 服务器域名白名单微信公众平台 → 开发 → 开发管理 → 开发设置 → 服务器域名uploadFile 合法域名OSS 的 bucket 域名如https://xxx.oss-cn-hangzhou.aliyuncs.comrequest 合法域名自家 API 域名 若用 PUT 直传 OSSOSS 域名也要加域名不对的表现uploadFile:fail url not in domain list不是代码 bug。2. 只用 HTTPSOSS 和小程序都要求 HTTPS代码里把http://统一替换成https://。3. 超时单文件上传建议设 30s 超时超时后标记失败、允许重试别一直 loading。容易踩的坑1. 用 wx.request 模拟 multipart 表单表单上传请用wx.uploadFile。自己拼 multipart body 在微信里又麻烦又容易错 boundary。2. V1 / V4 签名混用鉴权响应里如果出现x-oss-signature-version且含 OSS4就不能再走OSSAccessKeyId policy signature那套 V1 formData。3. STS 漏传 token临时凭证场景x-oss-security-token表单字段或 PUT header缺了必 403。预签名 URL 里已带 token 就别重复加 header。4. Content-Type 不一致PUT 上传时 header 里的类型必须和签名时一致jpg 就传image/jpeg别默认 octet-stream分片除外。5. 大文件 readFile 爆内存整文件 PUT 会把文件读进内存。图片压缩后一般 OK大视频要分片或走后端中转。6. 只传 OSS 不调完成接口对象在桶里有了业务系统没记录等于白传。7. 文件名 / key 重复纯时间戳命名高并发会撞名。MD5 随机数能缓解最终仍以 OSS 返回为准。8. 进度条假死uploadFile有onProgressUpdatePUT 分片要自己按已传字节算百分比。9. 秒传逻辑没接后端都返回「文件已存在」了前端还在传 OSS浪费用户流量和时间。组件层的一些实用细节如果封装成上传组件这几件事值得做本地 / 远程分状态isLocal标记待传文件已有fileId的跳过外部值同步加锁value/netImgs/netFileIds多个 prop 互相触发 observer 时用isSyncing防循环 setData批量顺序上传for...await一张一张传比并发更稳OSS 和小程序连接数都有限统一 emit上传完抛changeurls fileIds和uploadComplete表单页只关心结果失败可重试失败把uploading置 false、progress归零别卡在半成功状态后端需要配合什么前端能跑通后端至少提供三个能力鉴权根据 md5/大小/目录生成 OSS key返回上传凭证或秒传结果签名可选V4 或动态 policy 时单独签发完成上传OSS 对象落库返回可读地址和 fileId密钥、RAM 角色、STS 有效期、bucket 策略都在服务端配别下发到小程序。最小可用流程伪代码asyncfunctionuploadOne(tempPath,meta){constmd5awaitgetFileMd5(tempPath);constfileNamebuildFileName(tempPath,md5);constauthawaitapi.post(/upload/auth,{file_md5:md5,file_name:fileName,file_size:meta.size,file_dir:wx_app/images,type:meta.mime});if(auth.upload_statusINSTANT){returnauth;// 秒传}if(auth.server_typeoss){if(hasFormPolicy(auth)){awaitossFormUpload(tempPath,auth);}elseif(hasPresignedUrl(auth)){awaitossPutUpload(tempPath,auth);}else{constsignawaitapi.post(/upload/sign,{file_path:auth.file_path});awaitossFormUpload(tempPath,{...auth,...sign});}}else{awaitchunkPutUpload(tempPath,auth.chunk_urls);}returnapi.post(/upload/finish,{file_id:auth.file_id,file_md5:md5});}小结微信小程序传 OSS核心就一句话后端签发、前端直传、完成后回调。选型上小图优先wx.uploadFile表单 POST有预签名 URL 再用 PUT大文件走分片。上线前把 OSS 域名加进白名单、STS token 传对、完成接口接上这三件做到位大部分 403 和「传了但保存不了」的问题都能避开。如果你也在做类似组件建议先把鉴权响应打日志脱敏后看清楚后端到底走哪条分支再写上传逻辑比一上来硬套官方 demo 省时间得多。