传统模式云存储
CloudBase JS SDK v3 在传统模式下通过 app.storage.from() 提供云存储文件操作能力。传统模式面向环境内置云存储,上传时传入云存储相对路径,上传成功后返回完整 fileID;下载、删除、签名 URL、文件信息查询等操作建议使用完整 fileID。
传统模式调用云存储相关 API 时,使用的是 云存储 HTTP API 的开放能力。在使用前,请前往 云开发平台/身份认证/权限控制 确认 StoragesHttpApiAllow 的策略管理配置是否符合预期。详细说明请参考 策略管理说明文档。
传统模式与 PG 模式 API 的关键差异:
| 维度 | 传统模式 | PG 模式 |
|---|---|---|
| 入口 | app.storage.from() | app.storage.from("bucketId") |
| 路径参数 | cloud:// fileID | Bucket 内对象名,如 user-123/avatar.png |
| 权限模型 | 内置权限 + JSON 安全规则 | PostgreSQL RLS Policy |
| 覆盖默认值 | upsert 默认 true | upsert 默认 false |
| 图片转换 | download() / 签名 URL 支持 TransformOptions | 不支持 |
| 签名 URL 过期时间 | 支持 expiresIn / maxAge(小于 1 拒绝,大于 3600 警告后仍下发) | 支持 expiresIn |
| Bucket 管理 | 不支持 | 支持 createBucket / listBuckets 等 |
| 文件列表 | 不支持 | 支持 list() |
| 流式下载 | 不支持 | download().asStream() |
快速开始
import cloudbase from "@cloudbase/js-sdk";
const app = cloudbase.init({ env: "your-env-id" });
const storage = app.storage.from();
const { data, error } = await storage.upload("images/photo.jpg", file);
if (error) throw error;
const fileID = data.id;
const { data: blob } = await storage.download(fileID);
const { data: signed } = await storage.createSignedUrl(fileID, 3600);
await storage.remove([fileID]);
API 方法
客户端入口
- from() - 获取传统模式云存储文件操作客户端
- throwOnError() - 错误时抛出异常
文件操作
URL 管理
- createSignedUrl() - 创建签名 URL
- createSignedUrls() - 批量创建签名 URL
- getPublicUrl() - 获取公开 URL
- createSignedUploadUrl() - 创建上传签名 URL
文件信息
from
from(): ClassicStorageFileApi
参数
无参数
返回
传统模式 / 传统兼容对象操作客户端。
示例
const storage = app.storage.from();
throwOnError
throwOnError(): this
参数
无参数
返回
当前客户端实例,支持链式调用。
示例
const storage = app.storage.from().throwOnError();
await storage.upload("file.txt", file);
upload
上传文件到云存储。
upload(
path: string,
fileBody: FileBody,
fileOptions?: FileOptions
): Promise<
| { data: { id: string; path: string; fullPath: string }; error: null }
| { data: null; error: StorageError }
>
type FileBody = Blob | ArrayBuffer | ArrayBufferView | Uint8Array | string | { size?: number; byteLength?: number; [key: string]: any };
interface FileOptions {
cacheControl?: string;
contentType?: string;
metadata?: Record<string, any>;
upsert?: boolean; // 默认 true
}
参数
云存储相对路径,如 `images/photo.jpg`。
文件内容。
上传选项。传统模式默认 `upsert: true`。
返回
返回数据
错误信息。
示例
- 基础上传
- 带选项上传
// 上传文件
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);
}
// 上传文件并设置选项
const { data, error } = await app.storage
.from()
.upload("images/photo.jpg", file, {
cacheControl: "max-age=3600",
contentType: "image/jpeg",
metadata: {
author: "John Doe",
uploadedAt: new Date().toISOString(),
},
});
if (error) {
console.error("上传失败:", error);
} else {
console.log("上传成功:", data);
}
update
更新已存在的文件。
update(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);
}
// 更新文件并修改元数据
const { data, error } = await app.storage
.from()
.update("images/photo.jpg", newFile, {
cacheControl: "max-age=7200",
metadata: {
updatedAt: new Date().toISOString(),
version: "2.0",
},
});
if (error) {
console.error("更新失败:", error);
} else {
console.log("文件已更新:", data.path);
}
download
下载文件并返回内容。
download(
fileId: string,
options?: TransformOptions
): Promise<{ data: Blob; error: null } | { data: null; error: StorageError }>
interface TransformOptions {
width?: number;
height?: number;
quality?: number;
format?: "jpg" | "png" | "webp";
}
参数
完整 CloudBase fileID。
图片转换选项。
返回
文件内容。
错误信息。
示例
- 下载文件
- 下载缩略图
- 转换格式
// 下载原始文件
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();
}
// 下载并转换图片为缩略图
const { data: thumbnail, error } = await app.storage
.from()
.download("cloud://envId.xxx/images/photo.jpg", {
width: 300,
height: 200,
quality: 80,
});
if (thumbnail) {
// 显示缩略图
const url = URL.createObjectURL(thumbnail);
document.getElementById("thumbnail").src = url;
}
// 下载并转换图片格式
const { data: webpImage, error } = await app.storage
.from()
.download("cloud://envId.xxx/images/photo.jpg", {
format: "webp",
quality: 90,
});
if (webpImage) {
console.log("已转换为 WebP 格式");
}
remove
删除一个或多个文件。
remove(paths: string[]): Promise<{ data: FileObject[]; error: null } | { data: null; error: StorageError }>
参数
完整 fileID 数组。
返回
删除结果。
错误信息。
示例
- 删除单个文件
- 批量删除
// 删除单个文件
const { data, error } = await app.storage
.from()
.remove(["cloud://envId.xxx/images/photo.jpg"]);
if (error) {
console.error("删除失败:", error);
} else {
console.log("删除成功:", data);
}
// 批量删除多个文件
const { data, error } = await app.storage
.from()
.remove([
"cloud://envId.xxx/images/photo1.jpg",
"cloud://envId.xxx/images/photo2.jpg",
"cloud://envId.xxx/documents/file.pdf",
]);
if (error) {
console.error("删除失败:", error);
} else {
console.log(`成功删除 ${data.length} 个文件`);
}
move
移动文件到新位置。
move(fromPath: string, toPath: string): Promise<{ data: { message: string }; error: null } | { data: null; error: StorageError }>
参数
源路径。
目标路径。
返回
返回数据
错误信息。
示例
- 移动文件
- 重命名文件
// 移动文件到新位置
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);
}
// 重命名文件(移动到同一目录下的新名称)
const { data, error } = await app.storage
.from()
.move("images/photo.jpg", "images/new-photo.jpg");
if (error) {
console.error("重命名失败:", error);
} else {
console.log("重命名成功");
}
copy
复制文件到新位置。
copy(fromPath: string, toPath: string): Promise<{ data: { path: string }; error: null } | { data: null; error: StorageError }>
参数
源路径。
目标路径。
返回
返回数据
错误信息。
示例
- 复制文件
- 创建副本
// 复制文件到新位置
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);
}
// 在同一目录下创建副本
const { data, error } = await app.storage
.from()
.copy("images/photo.jpg", "images/photo-copy.jpg");
if (error) {
console.error("创建副本失败:", error);
} else {
console.log("副本已创建:", data.path);
}
createSignedUrl
创建文件临时访问链接。
createSignedUrl(
path: string,
expiresIn: number,
options?: { download?: string | boolean; transform?: TransformOptions }
): Promise<{ data: { signedUrl: string }; error: null } | { data: null; error: StorageError }>
expiresIn 单位为秒,会传给后端生成下载链接。须为大于等于 1 的整数;大于 3600 时控制台警告,仍按原值下发。小于 1 或非整数时返回错误、不发请求。旧版 getTempFileURL 的 maxAge 规则相同。
参数
完整 fileID。
过期时间(秒)。须为大于等于 1 的整数;大于 3600 时警告后仍按原值下发。
下载和图片转换选项。
返回
返回数据
错误信息。
示例
- 创建临时链接
- 创建缩略图链接
- 短期分享链接
// 创建 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);
// 可以直接使用这个链接访问文件
}
// 创建缩略图的临时链接
const { data, error } = await app.storage
.from()
.createSignedUrl("cloud://envId.xxx/images/photo.jpg", 3600, {
width: 300,
height: 200,
quality: 80,
});
if (error) {
console.error("创建失败:", error);
} else {
// 使用缩略图链接
document.getElementById("thumbnail").src = data.signedUrl;
}
// 创建 5 分钟有效的临时分享链接
const { data, error } = await app.storage
.from()
.createSignedUrl("cloud://envId.xxx/images/photo.jpg", 300);
if (error) {
console.error("创建失败:", error);
} else {
navigator.clipboard.writeText(data.signedUrl);
alert("分享链接已复制到剪贴板");
}
createSignedUrls
批量创建临时访问链接。
createSignedUrls(paths: string[], expiresIn: number): Promise<{ data, error }>
expiresIn 单位为秒,会传给后端生成下载链接。须为大于等于 1 的整数;大于 3600 时控制台警告,仍按原值下发。小于 1 或非整数时返回错误、不发请求。
参数
完整 fileID 数组。
过期时间(秒)。须为大于等于 1 的整数;大于 3600 时警告后仍按原值下发。
返回
签名链接结果数组。
错误信息。
示例
- 批量创建链接
- 批量创建缩略图链接
// 批量创建多个文件的临时链接
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}`);
});
}
// 批量创建缩略图链接
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 {
// 显示所有缩略图
const gallery = document.getElementById("gallery");
data.forEach((item) => {
const img = document.createElement("img");
img.src = item.signedUrl;
gallery.appendChild(img);
});
}
getPublicUrl
获取公开访问 URL。传统模式下底层走 createSignedUrl,返回的是临时 URL 而非永久公开直链,有效期固定为 600 秒。
getPublicUrl(path: string, options?: { download?: string | boolean; transform?: TransformOptions }): Promise<{ data: { publicUrl: string }; error: null } | { data: null; error: StorageError }>
参数
完整 fileID。
返回
返回数据
示例
- 获取公开链接
- 获取缩略图链接
// 获取文件的公开访问链接
const { data } = await app.storage
.from()
.getPublicUrl("cloud://envId.xxx/images/photo.jpg");
console.log("公开链接:", data.publicUrl);
// 可以直接使用这个链接(如果文件设置为公开访问)
// 获取缩略图的公开链接
const { data } = await app.storage
.from()
.getPublicUrl("cloud://envId.xxx/images/photo.jpg", {
width: 300,
height: 200,
quality: 80,
});
// 在 img 标签中使用
document.getElementById("thumbnail").src = data.publicUrl;
info
获取文件信息。
info(pathOrFileId: string): Promise<{ data: FileInfo; error: null } | { data: null; error: StorageError }>
参数
完整 fileID 或相对路径。
返回
文件信息。
错误信息。
示例
- 获取文件信息
- 显示文件详情
// 获取文件详细信息
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);
}
// 在界面上显示文件详情
const { data, error } = await app.storage
.from()
.info("cloud://envId.xxx/documents/report.pdf");
if (data) {
const sizeInMB = (data.size / 1024 / 1024).toFixed(2);
document.getElementById("fileName").textContent = data.name;
document.getElementById("fileSize").textContent = `${sizeInMB} MB`;
document.getElementById("createdAt").textContent = new Date(
data.created_at
).toLocaleString();
}
exists
检查文件是否存在。
exists(pathOrFileId: string): Promise<{ data: boolean; error: null } | { data: null; error: StorageError }>
参数
完整 fileID 或相对路径。
返回
是否存在。
错误信息。
示例
- 检查文件存在
- 上传前检查
// 检查文件是否存在
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("文件不存在");
}
// 上传前检查文件是否已存在
const { data: exists } = await app.storage
.from()
.exists("cloud://envId.xxx/images/photo.jpg");
if (exists) {
// 文件已存在,询问是否覆盖
const shouldOverwrite = confirm("文件已存在,是否覆盖?");
if (shouldOverwrite) {
await app.storage.from().update("images/photo.jpg", file);
}
} else {
// 文件不存在,直接上传
await app.storage.from().upload("images/photo.jpg", file);
}
createSignedUploadUrl
创建上传签名 URL。
createSignedUploadUrl(path: string): Promise<{ data, error }>
参数
上传目标路径。
返回
签名上传 URL 与 CloudBase 上传元信息。
错误信息。
示例
- 创建上传链接
- 客户端直传
// 创建用于上传的签名 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,
},
});
}
// 在客户端实现直传功能
async function uploadFileDirectly(file) {
// 1. 获取签名上传 URL
const { data, error } = await app.storage
.from()
.createSignedUploadUrl(`cloud://envId.xxx/uploads/${file.name}`);
if (error) {
console.error("获取上传 URL 失败:", error);
return;
}
// 2. 直接上传到云存储
const uploadResponse = await fetch(data.signedUrl, {
method: "PUT",
body: file,
headers: {
"Content-Type": file.type,
},
});
if (uploadResponse.ok) {
console.log("上传成功");
} else {
console.error("上传失败");
}
}
类型定义
type Result<T> =
| { data: T; error: null }
| { data: null; error: StorageError };
type FileBody = Blob | ArrayBuffer | ArrayBufferView | Uint8Array | string | { size?: number; byteLength?: number; [key: string]: any };
interface UploadResult {
id: string;
path: string;
fullPath: string;
}
interface FileOptions {
cacheControl?: string;
contentType?: string;
metadata?: Record<string, any>;
upsert?: boolean;
}
interface TransformOptions {
width?: number;
height?: number;
quality?: number;
format?: "jpg" | "png" | "webp";
}
迁移指南
如果你正在从 JS SDK v2 或旧版文件 API 迁移到 JS SDK v3 的传统模式云存储 API,可以按下表替换:
| 旧版 API | JS SDK v3 传统模式 API |
|---|---|
app.uploadFile() | app.storage.from().upload() |
app.downloadFile() | app.storage.from().download() |
app.getTempFileURL() | app.storage.from().createSignedUrl() |
app.deleteFile() | app.storage.from().remove() |
迁移时建议保存 upload() 返回的完整 fileID,并在下载、删除、生成签名 URL、查询信息时使用该值。getTempFileURL 的 maxAge 与 createSignedUrl 的 expiresIn 都会作为临时链接有效期(秒)下发:小于 1 或非整数拒绝,大于 3600 时警告后仍按原值下发。
最佳实践
1. 错误处理
const { data, error } = await app.storage.from().upload("images/photo.jpg", file);
if (error) {
console.error("操作失败:", error.message);
return;
}
2. 文件路径规范
- 上传时传入云存储相对路径,例如
images/photo.jpg。 - 下载、删除、签名 URL 和文件信息查询建议使用上传返回的完整
fileID。 - 路径不要以
/开头,不要包含连续/。