EdgeOne Makers Blob 存储
图片、视频、文档这类二进制大文件,用 KV 存储不合适,体积大、单值上限 10MB 根本存不下。EdgeOne Makers Blob 存储是专门的对象存储服务,用来存放这类非结构化数据,支持 CDN 加速分发,是文件存储的标准方案。
Blob 存储概念
Blob 的全称是 Binary Large Object,二进制大对象。它允许你把任意类型的文件,图片、视频、备份包、日志文件,统一以”对象”的形式存放在叫做 Bucket 的容器里。
每个对象由三部分组成:
| 组成部分 | 说明 |
|---|---|
| Key | 对象路径,类似文件名,例如 images/avatar.png |
| Data | 对象内容,二进制流 |
| Metadata | 自定义元数据,键值对形式 |
Blob 存储不关心内容是什么,只负责按 Key 存取,这种简单模型让它能横向扩展到几乎无限的容量。
与 KV 的定位区别
EdgeOne Makers 平台上有 KV 键值存储和 Blob 对象存储,两者各自定位不同。
| 对比项 | Blob 对象存储 | KV 键值存储 |
|---|---|---|
| 数据形态 | 二进制文件、大对象 | 字符串值 |
| 单条上限 | 单对象最大 5TB | 单值 10MB |
| 访问方式 | 通过 URL 或 API | 通过 API |
| CDN 集成 | 原生支持 | 不直接支持 |
| 典型场景 | 图片、视频、文档 | 配置、缓存、会话 |
简单记,Blob 存文件、KV 存配置。两者经常配合使用,例如 Blob 存原始图片、KV 存图片元数据。
创建 Bucket
Bucket 是对象的容器,类似一个顶级文件夹。一个账户下可以创建多个 Bucket,相互隔离。
在 EdgeOne Makers 控制台创建:
- 进入”存储” -> “Blob”页面
- 点击”创建 Bucket”
- 输入名称,比如
my-assets - 确认创建
Bucket 名称需要全局唯一,只能用小写字母、数字和短横线,长度 3 到 63 字符。
文件上传
上传文件有两种方式,控制台手动上传和 API 编程上传。
控制台上传
进入 Bucket 详情页,点击”上传”按钮,选择本地文件即可。适合手动测试和小批量维护。
API 上传
在函数代码里上传文件,用 put 方法:
export default {
async fetch(request, env) {
if (request.method !== "POST") {
return new Response("仅支持 POST", { status: 405 });
}
// 读取请求体中的文件数据
const formData = await request.formData();
const file = formData.get("file");
if (!file) {
return Response.json({ error: "缺少 file 字段" }, { status: 400 });
}
// 生成唯一路径
const key = `uploads/${Date.now()}-${file.name}`;
// 上传到 Blob
await env.MY_BLOB.put(key, file.stream(), {
httpMetadata: {
contentType: file.type,
},
});
return Response.json({ key, size: file.size });
},
};
字段说明:
| 字段 | 说明 |
|---|---|
| key | 对象路径,支持用斜杠模拟目录结构 |
| stream | 文件的可读流 |
| httpMetadata | HTTP 元数据,比如 contentType |
文件下载
通过 URL 直接访问
如果 Bucket 开启了公开访问,可以直接通过 URL 下载文件:
https://your-bucket.edgeone.app/images/avatar.png
这种方式最简单,适合公开资源。
通过函数代理下载
如果需要鉴权或控制访问,用函数代理:
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1); // 去掉开头的斜杠
// 从 Blob 读取文件
const object = await env.MY_BLOB.get(key);
if (!object) {
return new Response("文件不存在", { status: 404 });
}
// 构造响应
const headers = new Headers();
object.writeHttpMetadata(headers);
headers.set("etag", object.httpEtag);
return new Response(object.body, { headers });
},
};
文件列表
列出 Bucket 中的文件:
// 列出所有对象
const list = await env.MY_BLOB.list();
// 按前缀过滤
const images = await env.MY_BLOB.list({ prefix: "images/" });
// 限制返回数量
const limited = await env.MY_BLOB.list({ limit: 100 });
返回结果包含对象的 key、大小、上传时间等信息。
文件删除
删除单个对象:
await env.MY_BLOB.delete("uploads/old-file.png");
删除操作是即时的,删除后无法恢复,谨慎操作。
大文件处理
Blob 存储支持大文件,但上传和下载时需要注意内存和超时问题。
分片上传
对于超过 100MB 的大文件,建议用分片上传,避免单次请求内存爆炸:
// 伪代码示例,实际 API 可能不同
const chunkSize = 5 * 1024 * 1024; // 5MB 一片
let uploadId = await env.MY_BLOB.createMultipartUpload(key);
for (let i = 0; i < totalChunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
await env.MY_BLOB.uploadPart(key, uploadId, i + 1, chunk);
}
await env.MY_BLOB.completeMultipartUpload(key, uploadId);
流式读取
下载大文件时用流式读取,不要一次性加载到内存:
const object = await env.MY_BLOB.get(key);
// object.body 是 ReadableStream,可以直接 pipe 给响应
return new Response(object.body, {
headers: {
"content-type": object.httpMetadata.contentType,
},
});
这样无论文件多大,内存占用都很小。
最佳实践
路径设计
用斜杠模拟目录结构,方便管理:
| 好的路径 | 不好的路径 |
|---|---|
| images/2026/08/avatar.png | avatar.png |
| videos/course/01.mp4 | v1.mp4 |
| docs/report-2026.pdf | doc.pdf |
缓存策略
公开资源配合 CDN 缓存,设置合理的 Cache-Control:
headers.set("cache-control", "public, max-age=31536000");
静态图片、视频这类不常变的内容,缓存时间设长一些,减少回源次数。
访问控制
敏感文件不要开公开访问,用函数代理并加鉴权逻辑。公开资源可以开 CDN 加速,降低源站压力。
速查卡片
| 要点 | 说明 |
|---|---|
| Blob 是什么 | 对象存储,专门存二进制大文件 |
| 单文件上限 | 最大 5TB |
| 适合存什么 | 图片、视频、文档、备份 |
| 访问方式 | URL 直接访问或函数代理 |
| CDN 集成 | 原生支持,适合公开资源分发 |
| 大文件处理 | 分片上传、流式读取 |
| 路径设计 | 用斜杠模拟目录,如 images/2026/avatar.png |
| 访问控制 | 公开资源开 CDN,敏感文件加鉴权 |