必须使用sts临时凭证(accesskeyid、accesskeysecret、securitytoken)配合前端签名上传,否则因oss安全机制会返回403错误;formdata需包含ossaccesskeyid、policy、signature、x-oss-security-token、key和success_action_status字段,并按各端要求配置域名与跨域。

直接用 uni.uploadFile 上传就行,但必须配对使用后端下发的临时凭证(STS Token)和前端生成的签名,否则会报 403 Forbidden 或 InvalidAccessKeyId 错误。
为什么不能直接传?OSS 不允许裸密访问
阿里云 OSS 默认拒绝任何未授权的上传请求。即使你把 AccessKeyId 和 AccessKeySecret 写死在前端,也会被拦截——这是安全机制强制要求的。所以必须走 STS 临时凭证流程:后端调用阿里云 RAM/STS 接口,返回 AccessKeyId、AccessKeySecret、SecurityToken 和过期时间,前端拿这三样东西去签 policy 并上传。
- 硬编码密钥 = 线上环境立刻被薅,所有 Bucket 可读可删
- 没传
x-oss-security-token字段 = 403,哪怕 signature 对了也失败 - policy 过期时间写成过去时 = 上传直接被拒,控制台看不到错误详情,只返回空响应
uni.uploadFile 的 formData 必须包含哪些字段?
不是只传图片就完事,OSS 直传靠的是表单上传(form-data),formData 里缺一不可:
-
OSSAccessKeyId:从 STS 接口拿到的临时 key -
policy:base64 编码后的策略 JSON(含 expiration 和 conditions) -
signature:用临时AccessKeySecret对policy做 HMAC-SHA1 签名 -
x-oss-security-token:STS 返回的 token,必须原样传,大小写敏感 -
key:上传后在 OSS 中的文件路径,建议带时间戳或 UUID 防重名 -
success_action_status:设为"200",否则默认返回 204,uni-app 拿不到响应体
示例片段:
const formData = {
OSSAccessKeyId: credentials.AccessKeyId,
policy: base64Policy,
signature: computedSignature,
'x-oss-security-token': credentials.SecurityToken,
key: `images/${Date.now()}_${Math.random().toString(36).substr(2, 9)}.jpg`,
success_action_status: '200'
}
微信小程序/H5/APP 各端跨域和域名配置差异
uni-app 全端兼容的前提是各平台网络策略不同,必须分别处理:
- 微信小程序:必须在「小程序管理后台」把 OSS 的
Bucket Endpoint(如https://xxx.oss-cn-hangzhou.aliyuncs.com)加进「request 合法域名」,否则uploadFile直接 fail - H5:需在 OSS 控制台开启 Bucket 的「CORS」,允许来源设为
*或你的域名,暴露头设为x-oss-security-token - APP(iOS/Android):不需要额外域名白名单,但 iOS 要在
Info.plist加NSAppTransportSecurity允许明文 HTTP(如果用的是 http 协议 endpoint) - 支付宝小程序:同微信,需在「开发者中心 → 小程序设置 → 网络域名」添加 OSS 地址
上传前加水印,Canvas drawImage 容易踩的坑
纯前端加水印本质是用 Canvas 重绘图片,但不同端 Canvas 行为不一致:
- 微信小程序 Canvas 的
drawImage不支持跨域图片,必须先用uni.downloadFile把临时路径转成本地绝对路径再加载 - H5 端若图片来自相册(
file://协议),Chrome 会报Origin null is not allowed,得用URL.createObjectURL(file)构造 blob URL - nvue 页面不支持
document.createElement('canvas'),要用uni.createCanvasContext替代,且必须指定id和canvasId - 文字水印用
fillText时,iOS 上字体可能不生效,建议预埋一个透明 PNG 图片水印更稳妥
真正跑通的链路是:选图 → 下载/转 blob → 创建 canvas → 绘制原图 → 叠加水印 → canvas.toDataURL 或 canvas.toTempFilePath → 得到新文件路径 → 上传
最常被忽略的是 SecurityToken 的有效期和 policy 的 expiration 时间必须匹配,且都得比上传耗时多留至少 30 秒余量;另外,key 字段如果含中文或特殊符号,某些安卓 WebView 会编码异常,建议只用字母、数字、下划线和斜杠。











