UniApp 上传图片到阿里云 OSS 教程
阿里云对象存储服务(Object Storage Service,简称 OSS)是阿里云提供的海量、安全、低成本、高可靠的云存储服务。本文档详细介绍了在 UniApp 中实现图片上传到阿里云 OSS 的完整流程和关键代码。通过使用 uni.uploadFile 结合 OSS 的表单上传方式,我们可以在移动应用中高效、安全地实现文件上传功能。通过遵循本文档的实践指南,开发者可以在 UniApp 项目
UniApp 上传图片到阿里云 OSS 教程
- 概述
本文档详细介绍了在 UniApp 项目中如何实现图片上传到阿里云 OSS 的功能。主要包括以下内容:
- 阿里云 OSS 上传原理
- 前端实现流程
- 关键代码解析
- 常见问题及解决方案
- 阿里云 OSS 上传原理
2.1 基本概念
阿里云对象存储服务(Object Storage Service,简称 OSS)是阿里云提供的海量、安全、低成本、高可靠的云存储服务。在移动应用中,我们通常采用 STS(Security Token Service)临时授权的方式进行上传,这种方式更加安全。
2.2 上传流程
-
客户端向应用服务器请求临时授权(STS Token)
-
应用服务器返回临时授权信息(AccessKeyId、AccessKeySecret、SecurityToken 等)
-
客户端使用这些临时凭证直接向 OSS 发起上传请求
-
OSS 验证请求合法性并存储文件
-
客户端接收上传结果
-
前端实现流程
3.1 完整流程
在我们的 UniApp 项目中,图片上传到 OSS 的完整流程如下:
- 用户点击上传按钮,弹出选择菜单(从相册选择或拍照上传)
- 用户选择图片或拍照后,获取临时文件路径
- 调用后端接口获取 OSS 临时授权信息
- 使用 uni.uploadFile 方法将图片直接上传到 OSS
- 上传成功后,更新界面显示已上传的图片
3.2 关键步骤
-
选择图片:使用 uni.chooseImage API 从相册选择或拍照获取图片
-
获取授权:调用后端接口获取 OSS 临时授权信息
-
生成签名:根据 OSS 规则生成 Policy 和 Signature
-
上传文件:使用 uni.uploadFile 直接上传到 OSS 服务器
-
处理结果:根据上传结果更新界面状态
-
关键代码解析
4.1 组件结构
组件主要包含两个部分:
-
未上传状态:显示上传按钮
-
已上传状态:显示图片预览、文件名和删除按钮
<!-- 上传按钮区域 --> <view class="upload-buttons" v-if="fileList.length === 0"> <button class="custom-upload-btn" @click="showUploadOptions"> <image class="upload-icon" src="/static/img/icon/上传.png"></image> <text class="upload-text">上传报告</text> </button> </view>
4.2 选择图片
用户可以通过相册选择或拍照两种方式上传图片:
// 显示上传选项菜单
showUploadOptions() {
uni.showActionSheet({
itemList: ['从相册选择', '拍照上传'],
success: (res) => {
switch (res.tapIndex) {
case 0: // 从相册选择
this.chooseFromAlbum();
break;
case 1: // 拍照上传
this.takePhoto();
break;
}
}
});
}
// 从相册选择图片
chooseFromAlbum() {
uni.chooseImage({
count: 1, // 最多选择1张图片
sizeType: ['compressed'], // 强制使用压缩图提高上传速度
sourceType: ['album'], // 从相册选择
success: (res) => {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
const tempFilePath = res.tempFilePaths[0];
const tempFile = {
path: tempFilePath,
name: this.getFileNameFromPath(tempFilePath)
};
this.uploadFile(tempFile);
}
}
});
}
4.3 获取 OSS 授权
从后端获取 OSS 临时授权信息:
// 上传文件到OSS
uploadFile(file) {
uni.showLoading({
title: '上传中...'
});
// 获取OSS Token
getOssToken().then((tokenRes) => {
if (!tokenRes || tokenRes.status !== 200) {
console.error("OSS Token 响应无效:", tokenRes);
uni.hideLoading();
uni.showToast({
title: 'OSS Token 响应无效',
icon: 'none'
});
return;
}
const data = tokenRes.data;
// 检查必要参数
if (!data.accessKeyId || !data.bucket || !data.filePath) {
console.error("OSS Token 数据不完整:", data);
uni.hideLoading();
uni.showToast({
title: 'OSS 配置不完整',
icon: 'none'
});
return;
}
try {
// 生成唯一文件名
const fileName = this.generateFileName(file.name);
const key = `${data.filePath}/${fileName}`;
// 上传文件
this.uploadWithOSSSDK(
file.path,
key,
data.bucket,
data.accessKeyId,
data.accessKeySecret,
data.securityToken
);
} catch (error) {
this.logError("上传准备失败", error);
uni.hideLoading();
uni.showToast({
title: '上传准备失败',
icon: 'none'
});
}
}).catch((err) => {
this.logError("获取OSS Token失败", err);
uni.hideLoading();
uni.showToast({
title: 'OSS Token获取失败',
icon: 'none'
});
});
}
4.4 生成签名
根据 OSS 规则生成 Policy 和 Signature:
// 生成policy和signature
generatePolicyAndSignature(key, accessKeySecret, securityToken) {
try {
// 设置policy过期时间(1小时后)
const expiration = new Date(Date.now() + 3600 * 1000).toISOString();
// 构建policy
const policyText = {
expiration: expiration,
conditions: [
["content-length-range", 0, 10485760], // 10MB限制
["starts-with", "$key", key.substring(0, key.lastIndexOf('/') + 1)] // 限制上传路径
]
};
// Base64编码policy
const policyBase64 = this.base64Encode(JSON.stringify(policyText));
// 生成signature
const signature = this.hmacSha1(policyBase64, accessKeySecret);
return {
policy: policyBase64,
signature: signature
};
} catch (error) {
console.error("生成policy和signature失败:", error);
throw error;
}
}
// HMAC-SHA1签名(使用crypto-js标准实现)
hmacSha1(message, key) {
try {
// 使用crypto-js生成HMAC-SHA1签名
const hash = CryptoJS.HmacSHA1(message, key);
const signature = CryptoJS.enc.Base64.stringify(hash);
return signature;
} catch (error) {
console.error("HMAC-SHA1签名生成失败:", error);
throw error;
}
}
4.5 上传文件
使用 uni.uploadFile 直接上传到 OSS:
// 使用uni.uploadFile进行上传
uploadWithUniUpload(filePath, key, bucket, accessKeyId, accessKeySecret, securityToken) {
try {
// 生成policy和signature
const { policy, signature } = this.generatePolicyAndSignature(key, accessKeySecret, securityToken);
// 构建OSS上传URL
const uploadUrl = `https://${bucket}.xxxx.aliyuncs.com`;
// 构建表单数据(按照OSS要求的格式)
const formData = {
'key': key,
'policy': policy,
'OSSAccessKeyId': accessKeyId,
'signature': signature,
'success_action_status': '200'
};
// 添加STS Token
if (securityToken) {
formData['x-oss-security-token'] = securityToken;
}
// 使用uni.uploadFile进行上传
const uploadTask = uni.uploadFile({
url: uploadUrl,
filePath: filePath,
name: 'file',
formData: formData,
success: (uploadRes) => {
if (uploadRes.statusCode === 200 || uploadRes.statusCode === 204) {
uni.hideLoading();
const fileUrl = `https://${bucket}.xxxx.aliyuncs.com/${key}`;
this.fileList = [{
name: this.getFileNameFromPath(key),
url: fileUrl,
ossKey: key
}];
this.emitInput(key);
uni.showToast({
title: '上传成功',
icon: 'success'
});
} else {
console.error("uni.uploadFile上传失败,状态码:", uploadRes.statusCode);
uni.hideLoading();
uni.showToast({
title: `上传失败(${uploadRes.statusCode})`,
icon: 'none'
});
}
},
fail: (err) => {
console.error("uni.uploadFile上传失败:", err);
uni.hideLoading();
uni.showToast({
title: '上传失败',
icon: 'none'
});
}
});
// 监听上传进度
uploadTask.onProgressUpdate((res) => {
console.log('上传进度:', res.progress + '%');
});
} catch (error) {
console.error("生成上传参数失败:", error);
uni.hideLoading();
uni.showToast({
title: '上传参数生成失败',
icon: 'none'
});
}
}
- 后端接口
后端需要提供一个获取 OSS 临时授权的接口,返回以下信息:
// 获取OSS上传Token
export function getOssToken() {
return axios.post('/demo/oss/remote/getOssToken.action')
}
接口返回数据格式:
{
"status": 200,
"data": {
"accessKeyId": "临时AccessKeyId",
"accessKeySecret": "临时AccessKeySecret",
"securityToken": "临时SecurityToken",
"bucket": "OSS存储桶名称",
"filePath": "文件存储路径前缀"
}
}
- 常见问题及解决方案
6.1 上传失败问题
问题1:签名验证失败
可能原因:
- Policy 或 Signature 生成错误
- AccessKeySecret 使用错误
解决方案:
- 确保 Policy 格式正确,包含必要的条件限制
- 检查 HMAC-SHA1 签名算法实现是否正确
- 验证 AccessKeySecret 是否正确传递
问题2:权限不足
可能原因:
- STS Token 权限配置不足
- Bucket 权限设置限制
解决方案:
- 检查后端 STS Token 授权策略是否包含足够的权限
- 确认 Bucket 的访问控制设置是否允许上传
6.2 兼容性问题
问题:不同平台上传方式差异
解决方案:
- 针对安卓平台,直接使用 uni.uploadFile 方法
- 确保正确处理文件路径,特别是在不同平台下的路径格式差异
-
最佳实践
-
安全性:
- 始终使用 STS 临时授权方式,避免使用永久 AccessKey
- 设置合理的 Policy 限制,如文件大小、上传路径等
-
性能优化:
- 上传前压缩图片(sizeType: [‘compressed’])
- 监控上传进度并提供反馈
- 处理网络异常情况,提供重试机制
-
用户体验:
- 提供上传进度反馈
- 上传成功后立即显示预览
- 提供删除已上传文件的功能
-
总结
本文档详细介绍了在 UniApp 中实现图片上传到阿里云 OSS 的完整流程和关键代码。通过使用 uni.uploadFile 结合 OSS 的表单上传方式,我们可以在移动应用中高效、安全地实现文件上传功能。
关键点包括:
- 获取 OSS 临时授权信息
- 正确生成 Policy 和 Signature
- 使用 uni.uploadFile 直接上传到 OSS
- 处理上传结果和异常情况
通过遵循本文档的实践指南,开发者可以在 UniApp 项目中轻松实现图片上传到阿里云 OSS 的功能。
更多推荐
所有评论(0)