云开发云存储
概述
云开发云存储为您提供高可用、高稳定、强安全的云端存储服务,支持任意数量和形式的非结构化数据存储,如视频和图片等。在云函数中,您可以通过 Node.js SDK 或 HTTP API 两种方式访问云存储,实现文件的上传、下载、删除和管理等操作。
云存储的特点
- 安全可靠:提供多重数据备份,确保数据安全
- 弹性扩展:支持海量文件存储,按需付费
- 高性能:全球 CDN 加速,快速访问
- 权限控制:灵活的访问权限管理
- 多格式支持:支持图片、视频、文档等各种文件格式
📄️ Node.js SDK 访问
使用 Node.js SDK 在云函数中操作云存储
📄️ HTTP API 访问
通过 HTTP API 接口访问云存储服务
📄️ 文件操作
文件上传、下载、删除等基础操作
📄️ 高级功能
批量操作、权限管理、CDN 加速等高级特性
Node.js SDK 访问
初始化配置
在云函数中使用云存储前,需要先初始化 SDK:
const tcb = require('@cloudbase/node-sdk');
// 初始化云开发
const app = tcb.init({
env: 'your-env-id',
secretId: 'your-secret-id',
secretKey: 'your-secret-key'
});
// 获取云存储实例
const storage = app.storage();
文件上传
- Buffer 上传
- 流式上传
- 批量上传
exports.main = async (event, context) => {
try {
// 从事件中获取文件数据(Base64 编码)
const { fileContent, fileName, contentType } = event;
// 将 Base64 转换为 Buffer
const buffer = Buffer.from(fileContent, 'base64');
// 上传文件
const result = await storage.uploadFile({
cloudPath: `uploads/${Date.now()}_${fileName}`, // 云端路径
fileContent: buffer, // 文件内容
contentType: contentType || 'application/octet-stream' // 文件类型
});
return {
success: true,
fileID: result.fileID,
downloadURL: result.download_url,
message: '文件上传成功'
};
} catch (error) {
console.error('文件上传失败:', error);
return {
success: false,
error: error.message
};
}
};
const fs = require('fs');
const path = require('path');
exports.main = async (event, context) => {
try {
// 创建临时文件
const tempFilePath = `/tmp/${Date.now()}_temp_file`;
const { fileContent, fileName } = event;
// 写入临时文件
fs.writeFileSync(tempFilePath, Buffer.from(fileContent, 'base64'));
// 创建读取流
const fileStream = fs.createReadStream(tempFilePath);
// 上传文件流
const result = await storage.uploadFile({
cloudPath: `streams/${fileName}`,
fileContent: fileStream
});
// 清理临时文件
fs.unlinkSync(tempFilePath);
return {
success: true,
fileID: result.fileID,
downloadURL: result.download_url
};
} catch (error) {
console.error('流式上传失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { files } = event; // files 是文件数组
// 并行上传多个文件
const uploadPromises = files.map(async (file, index) => {
const buffer = Buffer.from(file.content, 'base64');
return await storage.uploadFile({
cloudPath: `batch/${Date.now()}_${index}_${file.name}`,
fileContent: buffer,
contentType: file.type
});
});
const results = await Promise.all(uploadPromises);
return {
success: true,
files: results.map(result => ({
fileID: result.fileID,
downloadURL: result.download_url
})),
message: `成功上传 ${results.length} 个文件`
};
} catch (error) {
console.error('批量上传失败:', error);
return {
success: false,
error: error.message
};
}
};
文件下载
- 获取下载链接
- 下载文件内容
- 批量下载
exports.main = async (event, context) => {
try {
const { fileID } = event;
// 获取文件下载链接
const result = await storage.getFileDownloadURL({
fileList: [fileID]
});
if (result.fileList && result.fileList.length > 0) {
const fileInfo = result.fileList[0];
return {
success: true,
downloadURL: fileInfo.download_url,
tempFileURL: fileInfo.tempFileURL,
maxAge: fileInfo.maxAge
};
} else {
throw new Error('文件不存在');
}
} catch (error) {
console.error('获取下载链接失败:', error);
return {
success: false,
error: error.message
};
}
};
const axios = require('axios');
exports.main = async (event, context) => {
try {
const { fileID } = event;
// 获取下载链接
const urlResult = await storage.getFileDownloadURL({
fileList: [fileID]
});
const downloadURL = urlResult.fileList[0].download_url;
// 下载文件内容
const response = await axios({
method: 'GET',
url: downloadURL,
responseType: 'arraybuffer'
});
// 转换为 Base64
const base64Content = Buffer.from(response.data).toString('base64');
return {
success: true,
content: base64Content,
contentType: response.headers['content-type'],
size: response.data.length
};
} catch (error) {
console.error('下载文件失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { fileIDs } = event; // 文件 ID 数组
// 批量获取下载链接
const result = await storage.getFileDownloadURL({
fileList: fileIDs
});
// 并行下载文件内容
const downloadPromises = result.fileList.map(async (fileInfo) => {
try {
const response = await axios({
method: 'GET',
url: fileInfo.download_url,
responseType: 'arraybuffer',
timeout: 30000
});
return {
fileID: fileInfo.fileID,
success: true,
content: Buffer.from(response.data).toString('base64'),
size: response.data.length
};
} catch (error) {
return {
fileID: fileInfo.fileID,
success: false,
error: error.message
};
}
});
const downloads = await Promise.all(downloadPromises);
return {
success: true,
files: downloads,
summary: {
total: downloads.length,
success: downloads.filter(d => d.success).length,
failed: downloads.filter(d => !d.success).length
}
};
} catch (error) {
console.error('批量下载失败:', error);
return {
success: false,
error: error.message
};
}
};
文件删除
- 删除单个文件
- 批量删除
exports.main = async (event, context) => {
try {
const { fileID } = event;
// 删除文件
const result = await storage.deleteFile({
fileList: [fileID]
});
if (result.fileList && result.fileList.length > 0) {
const deleteResult = result.fileList[0];
if (deleteResult.code === 'SUCCESS') {
return {
success: true,
message: '文件删除成功'
};
} else {
throw new Error(deleteResult.message || '删除失败');
}
}
} catch (error) {
console.error('删除文件失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { fileIDs } = event; // 文件 ID 数组
// 批量删除文件
const result = await storage.deleteFile({
fileList: fileIDs
});
const deleteResults = result.fileList || [];
const successCount = deleteResults.filter(item => item.code === 'SUCCESS').length;
const failedCount = deleteResults.length - successCount;
return {
success: failedCount === 0,
summary: {
total: deleteResults.length,
success: successCount,
failed: failedCount
},
details: deleteResults.map(item => ({
fileID: item.fileID,
success: item.code === 'SUCCESS',
message: item.message
}))
};
} catch (error) {
console.error('批量删除失败:', error);
return {
success: false,
error: error.message
};
}
};
HTTP API 访问
基础配置
使用 HTTP API 访问云存储需要先进行认证配置:
const axios = require('axios');
// HTTP API 基础配置
const config = {
baseURL: 'https://your-env-id.api.tcloudbasegateway.com',
accessToken: 'your-access-token' // 通过身份验证获取的访问令牌
};
// 发送 HTTP 请求的通用方法
async function callStorageAPI(endpoint, method = 'POST', data = null) {
try {
const response = await axios({
method: method,
url: `${config.baseURL}${endpoint}`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${config.accessToken}`
},
data: data
});
return response.data;
} catch (error) {
console.error('HTTP API 调用失败:', error);
throw error;
}
}
获取对象上传信息
- 获取上传信息
- 直传文件
- 批量上传
exports.main = async (event, context) => {
try {
const { objectIds } = event; // 对象 ID 数组
// 构建请求体
const requestBody = objectIds.map(objectId => ({
objectId: objectId
}));
// 调用获取对象上传信息 API
const result = await callStorageAPI('/v1/storages/get-objects-upload-info', 'POST', requestBody);
// 处理响应结果
const uploadInfos = result.map(item => {
if (item.code) {
// 失败的情况
return {
objectId: item.objectId,
success: false,
error: {
code: item.code,
message: item.message
}
};
} else {
// 成功的情况
return {
objectId: item.objectId,
success: true,
uploadUrl: item.uploadUrl,
downloadUrl: item.downloadUrl,
downloadUrlEncoded: item.downloadUrlEncoded,
token: item.token,
authorization: item.authorization,
cloudObjectMeta: item.cloudObjectMeta,
cloudObjectId: item.cloudObjectId
};
}
});
return {
success: true,
uploadInfos: uploadInfos
};
} catch (error) {
console.error('获取上传信息失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { objectId, fileContent } = event; // objectId: 文件路径,fileContent: Base64编码的文件内容
// 第一步:获取上传信息
const uploadInfoResult = await callStorageAPI('/v1/storages/get-objects-upload-info', 'POST', [
{ objectId: objectId }
]);
if (uploadInfoResult.length === 0 || uploadInfoResult[0].code) {
throw new Error(uploadInfoResult[0]?.message || '获取上传信息失败');
}
const uploadInfo = uploadInfoResult[0];
// 第二步:使用返回的信息直传文件
const fileBuffer = Buffer.from(fileContent, 'base64');
const uploadResponse = await axios({
method: 'PUT',
url: uploadInfo.uploadUrl,
headers: {
'Authorization': uploadInfo.authorization,
'X-Cos-Security-Token': uploadInfo.token,
'X-Cos-Meta-Fileid': uploadInfo.cloudObjectMeta,
'Content-Type': 'application/octet-stream'
},
data: fileBuffer
});
if (uploadResponse.status === 200) {
return {
success: true,
objectId: objectId,
cloudObjectId: uploadInfo.cloudObjectId,
downloadUrl: uploadInfo.downloadUrl,
downloadUrlEncoded: uploadInfo.downloadUrlEncoded,
message: '文件上传成功'
};
} else {
throw new Error('文件上传失败');
}
} catch (error) {
console.error('直传文件失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { files } = event; // files: [{ objectId, fileContent }]
// 第一步:批量获取上传信息
const objectIds = files.map(file => ({ objectId: file.objectId }));
const uploadInfoResults = await callStorageAPI('/v1/storages/get-objects-upload-info', 'POST', objectIds);
// 第二步:并行上传文件
const uploadPromises = files.map(async (file, index) => {
const uploadInfo = uploadInfoResults[index];
if (uploadInfo.code) {
return {
objectId: file.objectId,
success: false,
error: uploadInfo.message
};
}
try {
const fileBuffer = Buffer.from(file.fileContent, 'base64');
const uploadResponse = await axios({
method: 'PUT',
url: uploadInfo.uploadUrl,
headers: {
'Authorization': uploadInfo.authorization,
'X-Cos-Security-Token': uploadInfo.token,
'X-Cos-Meta-Fileid': uploadInfo.cloudObjectMeta,
'Content-Type': 'application/octet-stream'
},
data: fileBuffer,
timeout: 30000 // 30秒超时
});
return {
objectId: file.objectId,
success: true,
cloudObjectId: uploadInfo.cloudObjectId,
downloadUrl: uploadInfo.downloadUrl
};
} catch (error) {
return {
objectId: file.objectId,
success: false,
error: error.message
};
}
});
const results = await Promise.all(uploadPromises);
const successCount = results.filter(r => r.success).length;
const failedCount = results.length - successCount;
return {
success: failedCount === 0,
summary: {
total: results.length,
success: successCount,
failed: failedCount
},
results: results
};
} catch (error) {
console.error('批量上传失败:', error);
return {
success: false,
error: error.message
};
}
};
文件下载 API
exports.main = async (event, context) => {
try {
const { objectId } = event;
// 获取上传信息(包含下载链接)
const result = await callStorageAPI('/v1/storages/get-objects-upload-info', 'POST', [
{ objectId: objectId }
]);
if (result.length === 0 || result[0].code) {
throw new Error(result[0]?.message || '获取文件信息失败');
}
const fileInfo = result[0];
return {
success: true,
objectId: objectId,
downloadUrl: fileInfo.downloadUrl,
downloadUrlEncoded: fileInfo.downloadUrlEncoded,
cloudObjectId: fileInfo.cloudObjectId
};
} catch (error) {
console.error('获取下载链接失败:', error);
return {
success: false,
error: error.message
};
}
};
文件删除 API
// 注意:官方文档中的获取上传信息 API 主要用于上传,删除操作需要使用其他 API
// 这里提供一个通用的删除方法示例
exports.main = async (event, context) => {
try {
const { fileIds } = event; // 云存储文件 ID 数组
// 调用删除文件 API(具体端点根据实际 API 文档调整)
const result = await callStorageAPI('/v1/storages/delete-files', 'POST', {
fileIds: fileIds
});
return {
success: true,
result: result,
message: '文件删除请求已发送'
};
} catch (error) {
console.error('删除文件失败:', error);
return {
success: false,
error: error.message
};
}
};
文件操作
图片处理
- 图片缩放
- 图片水印
exports.main = async (event, context) => {
try {
const { fileID, width, height, quality } = event;
// 获取原始下载链接
const urlResult = await storage.getFileDownloadURL({
fileList: [fileID]
});
const originalURL = urlResult.fileList[0].download_url;
// 构建图片处理参数
const imageParams = [];
if (width) imageParams.push(`w_${width}`);
if (height) imageParams.push(`h_${height}`);
if (quality) imageParams.push(`q_${quality}`);
// 生成处理后的图片链接
const processedURL = `${originalURL}?imageView2/2/${imageParams.join('/')}`;
return {
success: true,
originalURL: originalURL,
processedURL: processedURL,
params: imageParams.join('/')
};
} catch (error) {
console.error('图片处理失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { fileID, watermarkText, position, opacity } = event;
// 获取原始下载链接
const urlResult = await storage.getFileDownloadURL({
fileList: [fileID]
});
const originalURL = urlResult.fileList[0].download_url;
// 构建水印参数
const watermarkParams = [
'watermark/2', // 文字水印
`text/${Buffer.from(watermarkText).toString('base64')}`, // 水印文字
`gravity/${position || 'southeast'}`, // 位置
`dissolve/${opacity || 80}` // 透明度
];
const watermarkedURL = `${originalURL}?${watermarkParams.join('/')}`;
return {
success: true,
originalURL: originalURL,
watermarkedURL: watermarkedURL
};
} catch (error) {
console.error('添加水印失败:', error);
return {
success: false,
error: error.message
};
}
};
文件信息查询
exports.main = async (event, context) => {
try {
const { fileID } = event;
// 获取文件信息
const urlResult = await storage.getFileDownloadURL({
fileList: [fileID]
});
if (urlResult.fileList && urlResult.fileList.length > 0) {
const fileInfo = urlResult.fileList[0];
// 获取文件详细信息
const response = await axios.head(fileInfo.download_url);
return {
success: true,
fileID: fileID,
downloadURL: fileInfo.download_url,
size: response.headers['content-length'],
contentType: response.headers['content-type'],
lastModified: response.headers['last-modified'],
etag: response.headers['etag']
};
} else {
throw new Error('文件不存在');
}
} catch (error) {
console.error('获取文件信息失败:', error);
return {
success: false,
error: error.message
};
}
};
文件列表查询
exports.main = async (event, context) => {
try {
const { prefix, limit, offset } = event;
// 注意:云存储 SDK 不直接支持文件列表查询
// 需要通过 COS SDK 或维护文件索引来实现
// 这里提供一个通过数据库维护文件索引的示例
const db = app.database();
const collection = db.collection('file_index');
let query = collection;
// 按前缀过滤
if (prefix) {
query = query.where({
cloudPath: db.RegExp({
regexp: `^${prefix}`,
options: 'i'
})
});
}
// 分页查询
const result = await query
.skip(offset || 0)
.limit(limit || 20)
.orderBy('uploadTime', 'desc')
.get();
return {
success: true,
files: result.data,
total: result.data.length,
hasMore: result.data.length === (limit || 20)
};
} catch (error) {
console.error('查询文件列表失败:', error);
return {
success: false,
error: error.message
};
}
};
高级功能
权限管理
- 设置公开读
- 私有访问控制
exports.main = async (event, context) => {
try {
const { fileID } = event;
// 获取下载链接(永久有效)
const result = await storage.getFileDownloadURL({
fileList: [{
fileID: fileID,
maxAge: 7200 // 2小时有效期
}]
});
if (result.fileList && result.fileList.length > 0) {
const fileInfo = result.fileList[0];
return {
success: true,
fileID: fileID,
publicURL: fileInfo.download_url,
maxAge: fileInfo.maxAge
};
}
} catch (error) {
console.error('设置公开读权限失败:', error);
return {
success: false,
error: error.message
};
}
};
exports.main = async (event, context) => {
try {
const { fileID, userId, permission } = event;
// 在数据库中记录文件权限
const db = app.database();
const collection = db.collection('file_permissions');
await collection.add({
fileID: fileID,
userId: userId,
permission: permission, // 'read', 'write', 'delete'
createdAt: new Date(),
createdBy: context.requestId
});
return {
success: true,
message: '权限设置成功'
};
} catch (error) {
console.error('设置文件权限失败:', error);
return {
success: false,
error: error.message
};
}
};
// 检查文件访问权限
exports.checkPermission = async (event, context) => {
try {
const { fileID, userId, action } = event;
const db = app.database();
const collection = db.collection('file_permissions');
const result = await collection
.where({
fileID: fileID,
userId: userId,
permission: action
})
.get();
return {
success: true,
hasPermission: result.data.length > 0
};
} catch (error) {
console.error('检查权限失败:', error);
return {
success: false,
error: error.message
};
}
};
CDN 加速
exports.main = async (event, context) => {
try {
const { fileID, enableCDN } = event;
// 获取文件下载链接
const result = await storage.getFileDownloadURL({
fileList: [fileID]
});
let downloadURL = result.fileList[0].download_url;
if (enableCDN) {
// 替换为 CDN 域名(需要在云开发控制台配置)
downloadURL = downloadURL.replace(
/https:\/\/[^.]+\.tcb\.qcloud\.la/,
'https://your-cdn-domain.com'
);
}
return {
success: true,
originalURL: result.fileList[0].download_url,
cdnURL: downloadURL,
cdnEnabled: enableCDN
};
} catch (error) {
console.error('CDN 配置失败:', error);
return {
success: false,
error: error.message
};
}
};
文件同步
exports.main = async (event, context) => {
try {
const { sourceFileID, targetPath, targetEnv } = event;
// 下载源文件
const downloadResult = await storage.getFileDownloadURL({
fileList: [sourceFileID]
});
const downloadURL = downloadResult.fileList[0].download_url;
// 下载文件内容
const response = await axios({
method: 'GET',
url: downloadURL,
responseType: 'arraybuffer'
});
// 初始化目标环境
const targetApp = tcb.init({
env: targetEnv,
secretId: process.env.SECRET_ID,
secretKey: process.env.SECRET_KEY
});
const targetStorage = targetApp.storage();
// 上传到目标环境
const uploadResult = await targetStorage.uploadFile({
cloudPath: targetPath,
fileContent: Buffer.from(response.data)
});
return {
success: true,
sourceFileID: sourceFileID,
targetFileID: uploadResult.fileID,
targetURL: uploadResult.download_url
};
} catch (error) {
console.error('文件同步失败:', error);
return {
success: false,
error: error.message
};
}
};
定时清理
exports.main = async (event, context) => {
try {
const { daysToKeep = 30, pathPrefix = 'temp/' } = event;
// 获取需要清理的文件列表(从数据库索引中查询)
const db = app.database();
const collection = db.collection('file_index');
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
const result = await collection
.where({
cloudPath: db.RegExp({
regexp: `^${pathPrefix}`,
options: 'i'
}),
uploadTime: db.command.lt(cutoffDate)
})
.get();
const filesToDelete = result.data;
if (filesToDelete.length === 0) {
return {
success: true,
message: '没有需要清理的文件',
deletedCount: 0
};
}
// 批量删除文件
const fileIDs = filesToDelete.map(file => file.fileID);
const deleteResult = await storage.deleteFile({
fileList: fileIDs
});
// 从数据库中删除记录
const deletePromises = filesToDelete.map(file =>
collection.doc(file._id).remove()
);
await Promise.all(deletePromises);
return {
success: true,
deletedCount: fileIDs.length,
message: `成功清理 ${fileIDs.length} 个过期文件`
};
} catch (error) {
console.error('定时清理失败:', error);
return {
success: false,
error: error.message
};
}
};
最佳实践
文件命名规范
// 生成规范的文件路径
function generateFilePath(category, userId, originalName) {
const timestamp = Date.now();
const randomStr = Math.random().toString(36).substr(2, 8);
const ext = path.extname(originalName);
const baseName = path.basename(originalName, ext);
// 清理文件名中的特殊字符
const cleanName = baseName.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
return `${category}/${userId}/${timestamp}_${randomStr}_${cleanName}${ext}`;
}
// 使用示例
const filePath = generateFilePath('avatars', 'user123', '用户头像.jpg');
// 输出: avatars/user123/1640995200000_abc12345_用户头像.jpg
文件类型验证
// 文件类型验证
function validateFileType(fileName, allowedTypes) {
const ext = path.extname(fileName).toLowerCase();
const mimeTypes = {
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.pdf': 'application/pdf',
'.doc': 'application/msword',
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
};
return allowedTypes.includes(ext) && mimeTypes[ext];
}
// 文件大小验证
function validateFileSize(fileContent, maxSizeMB) {
const buffer = Buffer.from(fileContent, 'base64');
const sizeMB = buffer.length / (1024 * 1024);
return sizeMB <= maxSizeMB;
}
// 使用示例
exports.main = async (event, context) => {
const { fileName, fileContent } = event;
// 验证文件类型
const allowedTypes = ['.jpg', '.jpeg', '.png', '.gif'];
const contentType = validateFileType(fileName, allowedTypes);
if (!contentType) {
return {
success: false,
error: '不支持的文件类型'
};
}
// 验证文件大小(限制 5MB)
if (!validateFileSize(fileContent, 5)) {
return {
success: false,
error: '文件大小超过限制(5MB)'
};
}
// 继续上传逻辑...
};
错误处理和重试
// 带重试机制的文件操作
async function executeWithRetry(operation, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
lastError = error;
// 判断是否为可重试的错误
if (isRetryableError(error) && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000; // 指数退避
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw lastError;
}
function isRetryableError(error) {
const retryableCodes = [
'ECONNRESET',
'ETIMEDOUT',
'ENOTFOUND',
'NETWORK_ERROR'
];
return retryableCodes.includes(error.code) ||
error.message.includes('timeout') ||
error.message.includes('network');
}
// 使用示例
exports.main = async (event, context) => {
try {
const result = await executeWithRetry(async () => {
return await storage.uploadFile({
cloudPath: event.path,
fileContent: Buffer.from(event.content, 'base64')
});
});
return { success: true, result };
} catch (error) {
console.error('文件操作最终失败:', error);
return { success: false, error: error.message };
}
};
性能优化
// 文件上传性能优化
class FileUploadOptimizer {
constructor() {
this.uploadQueue = [];
this.processing = false;
this.maxConcurrent = 3;
}
async addUpload(uploadTask) {
return new Promise((resolve, reject) => {
this.uploadQueue.push({ task: uploadTask, resolve, reject });
this.processQueue();
});
}
async processQueue() {
if (this.processing || this.uploadQueue.length === 0) {
return;
}
this.processing = true;
while (this.uploadQueue.length > 0) {
const batch = this.uploadQueue.splice(0, this.maxConcurrent);
const promises = batch.map(async ({ task, resolve, reject }) => {
try {
const result = await task();
resolve(result);
} catch (error) {
reject(error);
}
});
await Promise.all(promises);
}
this.processing = false;
}
}
// 全局上传优化器
const uploadOptimizer = new FileUploadOptimizer();
exports.main = async (event, context) => {
const { files } = event; // 多个文件
try {
const uploadTasks = files.map(file => () =>
storage.uploadFile({
cloudPath: generateFilePath('uploads', context.requestId, file.name),
fileContent: Buffer.from(file.content, 'base64')
})
);
const results = await Promise.all(
uploadTasks.map(task => uploadOptimizer.addUpload(task))
);
return {
success: true,
files: results.map(result => ({
fileID: result.fileID,
downloadURL: result.download_url
}))
};
} catch (error) {
console.error('批量上传失败:', error);
return {
success: false,
error: error.message
};
}
};
相关文档
📄️ Node.js SDK 存储 API
Node.js SDK 云存储的详细 API 文档
📄️ 云存储 HTTP API
云存储的 HTTP API 接口文档
提示
- 建议为不同类型的文件设置不同的存储路径
- 使用 CDN 加速可以显著提升文件访问速度
- 定期清理临时文件和过期文件以节省存储成本
- 重要文件建议设置备份和版本管理
注意
- 上传文件前务必进行类型和大小验证
- 敏感文件应设置适当的访问权限
- 避免在文件名中使用特殊字符
- 生产环境中建议配置文件访问监控和告警