手把手教你如使用七牛云对象存储,小程序和h5前端封装(附demo代码)
七牛云对象存储(Kodo)是一款稳定、安全、高效、易用的云存储服务,适用于各种场景下的数据存储需求。本文将详细介绍如何在项目中集成七牛云对象存储,并分别提供小程序端和H5端的实现代码。
·
七牛云对象存储(Kodo)是一款稳定、安全、高效、易用的云存储服务,适用于各种场景下的数据存储需求。本文将详细介绍如何在项目中集成七牛云对象存储,并分别提供小程序端和H5端的实现代码。
准备工作
1. 注册七牛云账号
首先访问七牛云官网注册账号并完成实名认证。
2. 创建存储空间(Bucket)
登录七牛云控制台后:
-
进入"对象存储"服务
-
点击"创建存储空间"
-
填写Bucket名称(需全局唯一)
-
选择存储区域(根据用户分布选择)
-
设置访问控制(建议先设置为公开,后续可按需调整)
3. 获取必要凭证
在"个人中心" > "密钥管理"中获取:
-
Access Key (AK)
-
Secret Key (SK)
核心讲解
一、核心上传流程
七牛云文件上传的核心流程分为三步:
-
获取上传凭证(uptoken)
-
初始化上传器并配置参数
-
执行上传并处理结果
二、前端核心代码
1. 初始化上传器
通用配置参数:
const config = {
bucket: 'your-bucket', // 存储空间名称
region: 'z0', // 存储区域(z0-华东,z1-华北等)
uptoken: '', // 上传凭证(通常从服务端获取)
domain: 'https://xxx.com', // 空间绑定的域名
shouldUseQiniuFileName: false // 是否使用七牛生成的文件名
};
2、获取服务端给的token和key(key可以是前端写死,但是最好还是用后端传的,交给后端来控制)
// 获取七牛云上传token
async function getQiniuUploadToken() {
try {
const res = await api.getQiniuAccesstoekn()
if (res.code !== 200) {
throw new Error(res.message || '获取七牛云token失败')
}
return res.data
}
catch (error) {
console.error('获取七牛云token失败:', error)
throw error
}
}
3、发起请求,上传文件
初始化上传任务
const observable = qiniu.upload(
file, // 文件对象/路径
key, // 文件保存的名称
config.uptoken, // 上传凭证
{ region: config.region }, // 额外配置
{ useCdnDomain: true } // 使用CDN加速
);
订阅上传进度
const subscription = observable.subscribe({
next: (res) => {
console.log('上传进度:', res.total.percent);
},
error: (err) => {
console.error('上传失败:', err);
reject(err);
},
complete: (res) => {
// 拼接完整URL
const fileUrl = `${config.domain}/${res.key}`;
console.log('上传完成:', fileUrl);
resolve({
...res,
fileUrl: fileUrl
});
}
});
封装demo(h5和小程序)
H5demo
import api from '@/api/module/cos'
import * as qiniu from 'qiniu-js'
// 七牛云配置
const qiniuConfig = {
uploadDomain: 'https://upload.qiniup.com' // 华东,
cdnDomain: 'cdn域名',
maxRetryCount: 2,
timeout: 3000,
}
// 获取七牛云上传token
async function getQiniuUploadToken() {
try {
const res = await api.getQiniuAccesstoekn()
if (res.code !== 200) {
throw new Error(res.message || '获取七牛云token失败')
}
return res.data
}
catch (error) {
console.error('获取七牛云token失败:', error)
throw error
}
}
/**
* 高级七牛云文件上传(H5版)
* @param {object} options 上传选项
* @param {File} options.file 文件对象
* @param {string} options.cloudPath 云端存储路径
* @param {Function} [options.onProgress] 上传进度回调
* @param {Function} [options.onCancel] 取消上传回调
* @param {number} [options.retryCount] 当前重试次数
* @returns {Promise<{url: string, key: string, hash: string}>} 上传结果
*/
async function uploadFileToQiniuH5(options) {
const {
file,
cloudPath,
onProgress = () => { },
onCancel = () => { },
retryCount = 0,
} = options
try {
// 获取上传token
const { token, key } = await getQiniuUploadToken()
const cloudFile = `${key}/${cloudPath}`
// 配置上传选项
const putExtra = {
fname: file.name,
params: {},
mimeType: file.type || null,
}
const config = {
useCdnDomain: true,
region: qiniu.region.z0, // 华东区域
retryCount: qiniuConfig.maxRetryCount,
disableStatisticsReport: false,
}
// 执行上传
return new Promise((resolve, reject) => {
let subscription = null
let timer = null
// 超时处理
timer = setTimeout(() => {
if (subscription) {
subscription.unsubscribe()
}
reject(new Error('上传超时'))
}, qiniuConfig.timeout)
const observable = qiniu.upload(
file,
cloudFile,
token,
putExtra,
config,
)
subscription = observable.subscribe({
next: (response) => {
// 进度更新
onProgress({
loaded: response.total.loaded,
total: response.total.size,
percent: Math.round(response.total.percent),
})
},
error: (err) => {
clearTimeout(timer)
// 重试逻辑
if (retryCount < qiniuConfig.maxRetryCount) {
console.log(`准备第${retryCount + 1}次重试...`)
setTimeout(() => {
uploadFileToQiniuH5({
...options,
retryCount: retryCount + 1,
}).then(resolve).catch(reject)
}, 1000 * (retryCount + 1))
}
else {
reject(new Error(`上传失败: ${err.message}`))
}
},
complete: (res) => {
clearTimeout(timer)
console.log('上传成功:', res)
resolve({
url: `${qiniuConfig.cdnDomain}/${res.key}`,
key: res.key,
hash: res.hash,
})
},
})
// 提供取消上传的方法
onCancel(() => {
clearTimeout(timer)
if (subscription) {
subscription.unsubscribe()
}
reject(new Error('上传已取消'))
})
})
}
catch (error) {
console.error('上传文件到七牛云失败:', error)
throw error
}
}
/**
* 简化版上传(H5版)
* @param {File} file 文件对象
* @param {string} cloudPath 云端存储路径
* @returns {Promise<string>} 文件URL
*/
async function simpleUploadH5(file, cloudPath) {
const result = await uploadFileToQiniuH5({
file,
cloudPath,
onProgress: (progress) => {
console.log(`上传进度: ${progress.percent}%`)
},
})
return result.url
}
export {
simpleUploadH5,
uploadFileToQiniuH5,
}
小程序demo
import { getQiniuAccesstoekn } from '../api/module/cos'
// 七牛云配置
const qiniuConfig = {
uploadDomain: 'https://upload.qiniup.com' //华东,
// 你的CDN域名
cdnDomain: 'cdn域名',
// 上传重试次数
maxRetryCount: 2,
timeout: 3000
};
// 获取七牛云上传token
const getQiniuUploadToken = async () => {
try {
const res = await getQiniuAccesstoekn();
if (res.code !== 200) {
throw new Error(res.message || '获取七牛云token失败');
}
return res.data;
} catch (error) {
console.error('获取七牛云token失败:', error);
throw error;
}
};
/**
* 高级七牛云文件上传
* @param {Object} options 上传选项
* @param {string} options.filePath 本地文件路径
* @param {string} options.cloudPath 云端存储路径
* @param {Function} [options.onProgress] 上传进度回调
* @param {Function} [options.onCancel] 取消上传回调
* @param {number} [options.retryCount=0] 当前重试次数
* @returns {Promise<{url: string, key: string, hash: string}>} 上传结果
*/
const uploadFileToQiniu = async (options) => {
const {
filePath,
cloudPath,
onProgress = () => { },
onCancel = () => { },
retryCount = 0
} = options;
try {
// 获取上传token
const { token, key } = await getQiniuUploadToken();
const cloudFile = `${key}/${cloudPath}`
// 获取文件信息
const fileInfo = await new Promise((resolve, reject) => {
wx.getFileInfo({
filePath,
success: resolve,
fail: reject
});
});
// 执行上传
return new Promise((resolve, reject) => {
let uploadTask = null;
let timer = null;
// 超时处理
timer = setTimeout(() => {
if (uploadTask) {
uploadTask.abort();
}
reject(new Error('上传超时'));
}, qiniuConfig.timeout);
uploadTask = wx.uploadFile({
url: qiniuConfig.uploadDomain,
filePath,
name: 'file',
formData: {
token,
key: cloudFile
},
success: (res) => {
clearTimeout(timer);
if (res.statusCode === 200) {
try {
const data = JSON.parse(res.data);
console.log('上传成功:', data);
resolve({
url: `${qiniuConfig.cdnDomain}/${data.key}`,
key: data.key,
hash: data.hash
});
} catch (e) {
reject(new Error('解析响应数据失败'));
}
} else {
reject(new Error(`上传失败: ${res.data}`));
}
},
fail: (err) => {
clearTimeout(timer);
// 重试逻辑
if (retryCount < qiniuConfig.maxRetryCount) {
console.log(`准备第${retryCount + 1}次重试...`);
setTimeout(() => {
uploadFileToQiniu({
...options,
retryCount: retryCount + 1
}).then(resolve).catch(reject);
}, 1000 * (retryCount + 1));
} else {
reject(new Error(`上传失败: ${err.errMsg}`));
}
},
complete: () => {
clearTimeout(timer);
}
});
// 确保uploadTask存在再绑定事件
if (uploadTask && uploadTask.onProgressUpdate) {
uploadTask.onProgressUpdate((res) => {
onProgress({
loaded: res.totalBytesSent,
total: res.totalBytesExpectedToSend,
percent: res.progress
});
});
}
// 提供取消上传的方法
onCancel(() => {
clearTimeout(timer);
if (uploadTask) {
uploadTask.abort();
}
reject(new Error('上传已取消'));
});
});
} catch (error) {
console.error('上传文件到七牛云失败:', error);
throw error;
}
};
/**
* 简化版上传
* @param {string} filePath 本地文件路径
* @param {string} cloudPath 云端存储路径
* @returns {Promise<string>} 文件URL
*/
const simpleUpload = async (filePath, cloudPath) => {
const result = await uploadFileToQiniu({
filePath,
cloudPath,
onProgress: (progress) => {
console.log(`上传进度: ${progress.percent}%`);
}
});
return result.url;
};
export {
uploadFileToQiniu,
simpleUpload
};
注意:在小程序端可以直接请求七牛云的域名,h5用七牛云的时候用qiniu.upload的时候报错,控制台说这个方法没有被定义,但是我是按照官方的文档写的,我用的版本是最新的4.X meta版本,但是换到3.1.2版本就不会有报错了,可能是API更新了官方的文档没有更新之类的,或者其他原因导致的
更多推荐
所有评论(0)