跳到主要内容

概述

快速开始

import cloudbase from "@cloudbase/js-sdk";

const app = cloudbase.init({
env: "your-env-id",
});

// 使用 Supabase 风格的 API
const storage = app.storage.from();

// 上传文件
const { data, error } = await storage.upload("images/photo.jpg", file);

// 下载文件
const { data: blob } = await storage.download(
"cloud://envId.xxx/images/photo.jpg"
);

// 创建签名 URL
const {
data: { signedUrl },
} = await storage.createSignedUrl(
"[images/photo.jpg](cloud://envId.xxx/images/photo.jpg)",
3600
);

// 删除文件
await storage.remove([
"[images/photo.jpg](cloud://envId.xxx/images/photo.jpg)",
]);

API 方法

链式调用

文件操作

URL 管理

文件信息


from

from(bucket?: string): this

指定要操作的存储桶,默认选中环境云存储桶。

示例:

const storage = app.storage.from();

throwOnError

throwOnError(): this

设置在发生错误时抛出异常,而不是返回错误对象。

示例:

const storage = app.storage.from().throwOnError();

try {
const { data } = await storage.upload("file.txt", file);
console.log("上传成功:", data);
} catch (error) {
console.error("上传失败:", error);
}

upload

upload(
path: string,
fileBody: FileBody,
fileOptions?: FileOptions
): Promise<{ data: { id: string; path: string; fullPath: string }; error: null } | { data: null; error: StorageError }>

上传文件到云存储。

参数

path
string

文件路径,如 'images/photo.jpg'

fileBody
FileBody

文件内容,支持 File、Blob、ArrayBuffer、Buffer、Stream 等类型

fileOptions
FileOptions

上传选项

返回

Promise
{ data, error }

示例

// 上传文件
const { data, error } = await app.storage
.from()
.upload("images/photo.jpg", file);

if (error) {
console.error("上传失败:", error);
} else {
console.log("上传成功:", data);
console.log("文件 ID:", data.id);
console.log("文件路径:", data.path);
}

update

update(
path: string,
fileBody: FileBody,
fileOptions?: FileOptions
): Promise<{ data: { id: string; path: string; fullPath: string }; error: null } | { data: null; error: StorageError }>

更新已存在的文件。

参数

path
string

文件路径

fileBody
FileBody

新的文件内容

fileOptions
FileOptions

上传选项

返回

Promise
{ data, error }

示例

// 更新文件内容
const { data, error } = await app.storage
.from()
.update("images/photo.jpg", newFile);

if (error) {
console.error("更新失败:", error);
} else {
console.log("更新成功:", data);
}

download

download(
fileId: string,
options?: TransformOptions
): Promise<{ data: Blob; error: null } | { data: null; error: StorageError }>

下载文件并返回 Blob 对象。支持图片转换功能。

参数

fileId
string

文件 ID

options
TransformOptions

图片转换选项(仅对图片有效)

返回

Promise
{ data, error }

示例

// 下载原始文件
const { data, error } = await app.storage
.from()
.download("cloud://envId.xxx/images/photo.jpg");

if (data) {
// 创建下载链接
const url = URL.createObjectURL(data);
const a = document.createElement("a");
a.href = url;
a.download = "photo.jpg";
a.click();
}

remove

remove(
fileIds: string[]
): Promise<{ data: { id: string }[]; error: null } | { data: null; error: StorageError }>

删除一个或多个文件。

参数

fileIds
string[]

要删除的文件 ID数组

返回

Promise
{ data, error }

示例

// 删除单个文件
const { data, error } = await app.storage
.from()
.remove(["cloud://envId.xxx/images/photo.jpg"]);

if (error) {
console.error("删除失败:", error);
} else {
console.log("删除成功:", data);
}

move

move(
fromPath: string,
toPath: string
): Promise<{ data: { message: string }; error: null } | { data: null; error: StorageError }>

移动文件到新位置。

参数

fromPath
string

源文件路径

toPath
string

目标文件路径

返回

Promise
{ data, error }

示例

// 移动文件到新位置
const { data, error } = await app.storage
.from()
.move("images/old-photo.jpg", "images/archive/photo.jpg");

if (error) {
console.error("移动失败:", error);
} else {
console.log("移动成功:", data.message);
}

copy

copy(
fromPath: string,
toPath: string
): Promise<{ data: { path: string }; error: null } | { data: null; error: StorageError }>

复制文件到新位置。

参数

fromPath
string

源文件路径

toPath
string

目标文件路径

返回

Promise
{ data, error }

示例

// 复制文件到新位置
const { data, error } = await app.storage
.from()
.copy("images/photo.jpg", "images/backup/photo.jpg");

if (error) {
console.error("复制失败:", error);
} else {
console.log("复制成功,新文件路径:", data.path);
}

createSignedUrl

createSignedUrl(
fileId: string,
expiresIn: number,
options?: TransformOptions
): Promise<{ data: { signedUrl: string }; error: null } | { data: null; error: StorageError }>

创建一个带签名的临时访问 URL。

参数

fileId
string

文件 ID

expiresIn
number

URL 有效期(秒)

options
TransformOptions

图片转换选项

返回

Promise
{ data, error }

示例

// 创建 1 小时有效的临时链接
const { data, error } = await app.storage
.from()
.createSignedUrl("cloud://envId.xxx/images/photo.jpg", 3600);

if (error) {
console.error("创建失败:", error);
} else {
console.log("临时链接:", data.signedUrl);
// 可以直接使用这个链接访问文件
}

createSignedUrls

createSignedUrls(
fileIds: string[],
expiresIn: number,
): Promise<{ data: Array<{ path: string; signedUrl: string }>; error: null } | { data: null; error: StorageError }>

批量创建带签名的临时访问 URL。

参数

fileIds
string[]

文件 ID数组

expiresIn
number

URL 有效期(秒)

返回

Promise
{ data, error }

示例

// 批量创建多个文件的临时链接
const { data, error } = await app.storage
.from()
.createSignedUrls(
[
"cloud://envId.xxx/images/photo1.jpg",
"cloud://envId.xxx/images/photo2.jpg",
"cloud://envId.xxx/images/photo3.jpg",
],
3600
);

if (error) {
console.error("创建失败:", error);
} else {
data.forEach((item) => {
console.log(`${item.path}: ${item.signedUrl}`);
});
}

getPublicUrl

getPublicUrl(
fileId: string,
options?: TransformOptions
): { data: { publicUrl: string } }

获取文件的公开访问 URL(不带签名)。

参数

fileId
string

文件 ID

options
TransformOptions

图片转换选项

返回

Object
{ data }

示例

// 获取文件的公开访问链接
const { data } = await app.storage
.from()
.getPublicUrl("cloud://envId.xxx/images/photo.jpg");

console.log("公开链接:", data.publicUrl);
// 可以直接使用这个链接(如果文件设置为公开访问)

info

info(
fileId: string
): Promise<{ data: FileInfo; error: null } | { data: null; error: StorageError }>

获取文件的详细信息。

参数

fileId
string

文件 ID

返回

Promise
{ data, error }

示例

// 获取文件详细信息
const { data, error } = await app.storage
.from()
.info("cloud://envId.xxx/images/photo.jpg");

if (error) {
console.error("获取失败:", error);
} else {
console.log("文件名:", data.name);
console.log("文件大小:", data.size, "字节");
console.log("创建时间:", data.created_at);
console.log("更新时间:", data.updated_at);
console.log("元数据:", data.metadata);
}

exists

exists(
fileId: string
): Promise<{ data: boolean; error: null } | { data: null; error: StorageError }>

检查文件是否存在。

参数

fileId
string

文件 ID

返回

Promise
{ data, error }

示例

// 检查文件是否存在
const { data: exists, error } = await app.storage
.from()
.exists("cloud://envId.xxx/images/photo.jpg");

if (error) {
console.error("检查失败:", error);
} else if (exists) {
console.log("文件存在");
} else {
console.log("文件不存在");
}

createSignedUploadUrl

createSignedUploadUrl(
fileId: string,
options?: { upsert?: boolean }
): Promise<{ data: { signedUrl: string; path: string; token: string }; error: null } | { data: null; error: StorageError }>

创建一个用于上传的签名 URL,允许客户端直接上传文件到云存储。

参数

fileId
string

文件 ID

options
Object

上传选项

返回

Promise
{ data, error }

示例

// 创建用于上传的签名 URL
const { data, error } = await app.storage
.from()
.createSignedUploadUrl("cloud://envId.xxx/images/photo.jpg");

if (error) {
console.error("创建失败:", error);
} else {
console.log("上传 URL:", data.signedUrl);
console.log("上传令牌:", data.token);

// 使用这个 URL 直接上传文件
const formData = new FormData();
formData.append("file", file);

await fetch(data.signedUrl, {
method: "PUT",
body: file,
headers: {
"Content-Type": file.type,
},
});
}

类型定义

FileBody

type FileBody = File | Blob | ArrayBuffer | Buffer | ReadableStream | string;

支持的文件内容类型。

FileOptions

interface FileOptions {
cacheControl?: string; // 缓存控制,如 'max-age=3600'
contentType?: string; // 文件 MIME 类型,如 'image/jpeg'
metadata?: Record<string, any>; // 自定义元数据
upsert?: boolean; // 是否覆盖已存在的文件
}

文件上传选项。

TransformOptions

interface TransformOptions {
width?: number; // 目标宽度
height?: number; // 目标高度
quality?: number; // 图片质量 (1-100)
format?: "jpg" | "png" | "webp"; // 输出格式
}

图片转换选项(仅对图片有效)。

FileInfo

interface FileInfo {
name: string; // 文件名
id: string; // 文件 ID
size: number; // 文件大小(字节)
created_at: string; // 创建时间
updated_at: string; // 更新时间
metadata?: Record<string, any>; // 自定义元数据
}

文件信息对象。

StorageError

interface StorageError {
message: string; // 错误消息
statusCode?: number; // HTTP 状态码
}

存储错误对象。


迁移指南

如果你正在使用传统的 CloudBase 云存储 API,建议迁移到 Supabase 风格的 API。以下是迁移对照表:

API 对照表

传统 APISupabase 风格 API说明
app.uploadFile()app.storage.from().upload()上传文件
app.getTempFileURL()app.storage.from().createSignedUrl()获取临时链接
app.deleteFile()app.storage.from().remove()删除文件
app.downloadFile()app.storage.from().download()下载文件

迁移示例

上传文件

// 传统方式
const result = await app.uploadFile({
cloudPath: "images/photo.jpg",
filePath: file,
});

console.log("文件 ID:", result.fileID);

获取临时链接

// 传统方式
const res = await app.getTempFileURL({
fileList: [
{
fileID: "cloud://envId.xxx/images/photo.jpg",
maxAge: 3600,
},
],
});

const url = res.fileList[0].tempFileURL;

删除文件

// 传统方式
const result = await app.deleteFile({
fileList: ["cloud://xxx.jpg"],
});

下载文件

// 传统方式
const result = await app.downloadFile({
fileID: "cloud://xxx.jpg",
});

最佳实践

1. 错误处理

始终检查错误对象:

const { data, error } = await app.storage.from().upload("file.txt", file);

if (error) {
console.error("操作失败:", error.message);
// 处理错误
return;
}

// 使用 data
console.log("操作成功:", data);

或者使用 throwOnError() 方法:

try {
const { data } = await app.storage
.from()
.throwOnError()
.upload("file.txt", file);

console.log("操作成功:", data);
} catch (error) {
console.error("操作失败:", error);
}

2. 文件路径规范

  • 使用 / 分隔目录
  • 不要以 / 开头
  • 使用有意义的目录结构
// ✅ 推荐
"images/avatars/user-123.jpg";
"documents/reports/2024/report.pdf";
"uploads/temp/file-abc.txt";

// ❌ 不推荐
"/images/photo.jpg"; // 不要以 / 开头
"photo.jpg"; // 缺少目录结构

3. 图片优化

使用图片转换选项优化加载速度:

// 获取缩略图
const { data } = await app.storage
.from()
.createSignedUrl("images/large-photo.jpg", 3600, {
width: 300,
height: 300,
quality: 80,
format: "webp", // 使用 WebP 格式减小文件大小
});

4. 批量操作

对于多个文件的操作,使用批量方法提高效率:

// ✅ 推荐:批量创建签名 URL
const { data } = await app.storage
.from()
.createSignedUrls(["image1.jpg", "image2.jpg", "image3.jpg"], 3600);

// ❌ 不推荐:逐个创建
for (const path of paths) {
await app.storage.from().createSignedUrl(path, 3600);
}

5. 缓存控制

合理设置缓存控制头:

// 静态资源:长期缓存
await app.storage.from().upload("images/logo.png", file, {
cacheControl: "max-age=31536000", // 1 年
});

// 动态内容:短期缓存
await app.storage.from().upload("data/report.json", file, {
cacheControl: "max-age=300", // 5 分钟
});

// 不缓存
await app.storage.from().upload("temp/data.txt", file, {
cacheControl: "no-cache",
});

常见问题

1. 如何处理大文件上传?

对于大文件,建议使用 createSignedUploadUrl() 实现客户端直传:

const { data } = await app.storage
.from()
.createSignedUploadUrl("large-file.zip");

// 使用 fetch 上传大文件
await fetch(data.signedUrl, {
method: "PUT",
body: largeFile,
});

2. 如何实现断点续传?

CloudBase 云存储暂不直接支持断点续传,建议将大文件分片上传:

async function uploadLargeFile(file, chunkSize = 5 * 1024 * 1024) {
const chunks = Math.ceil(file.size / chunkSize);

for (let i = 0; i < chunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);

await app.storage.from().upload(`temp/file-${i}`, chunk);
}

// 合并分片(需要云函数支持)
}

3. 如何设置文件访问权限?

文件访问权限需要在云开发控制台的"权限控制/策略管理"中配置。

4. 支持哪些图片格式转换?

支持 JPG、PNG、WebP 格式之间的相互转换。

5. 临时链接的最长有效期是多久?

建议不超过 7 天(604800 秒)。


相关资源