MuseMVP
MuseMVP 文档

对象存储

配置 R2 binding,理解上传限制、文件归属、下载响应和 API Key 调用。

模块与数据位置

packages/storage/src/index.ts 负责文件校验和 R2 操作,apps/web/src/server/files.ts 连接 HTTP、会话、配额与数据库。R2_BUCKET binding 保存正文,D1 保存原始文件名、MIME、大小、归属和对象键。默认文件是私有资源,不通过公开 bucket URL 直接分享。

本地启动使用 Wrangler 本地 R2,不需要先购买或创建远程 bucket。生产 bucket 由部署目标的资源规划绑定。修改名称前请阅读 部署指南,防止既有对象留在旧 bucket。

上传限制

项目当前默认
单文件大小大于 0,最多 1,048,576 字节(1 MiB)
文本类型text/plain、text/markdown
图片类型image/png、image/jpeg、image/webp
文件数量每用户 100 个,由 product.quotas.storedFiles 配置

文件数量是产品配置;单文件限制与允许 MIME 在 storage 包校验。调整时同步服务端、上传控件提示及测试,不能只放宽 HTML accept。

从工作台验证

  1. 打开 /app/files,上传一个小型 .txt 或图片。
  2. 查看文件名、大小和状态,刷新后仍能找到同一记录。
  3. 下载文件,确认字节内容正确。
  4. 删除后刷新列表,确认记录消失且不能再次下载。

对象键使用用户 ID 与随机 UUID,不直接使用上传文件名。下载以附件形式返回,使用私有且不缓存的响应策略,不直接让浏览器执行上传内容。

在自己的前端调用

const form = new FormData();
form.set('file', selectedFile);
const response = await fetch('/api/files', { method: 'POST', body: form });
if (!response.ok) throw new Error('Upload failed');

不要手工设置 multipart Content-Type,让浏览器生成 boundary。读取列表使用 GET /api/files;单文件下载和删除按当前 files.ts 中的 ID 路径调用,不向服务端提交任意 R2 key。

API Key 与归属检查

设置页创建的文件 API Key 通过 x-api-key 头提交,作用范围仅为文件接口。它仍受用户邮箱验证、封禁状态、配额和归属限制。不同用户即使知道文件 ID 也不能下载或删除。

存储上传成功但元数据写入失败时,现有实现清理刚上传的 R2 对象;删除先操作 R2 再删除元数据。扩展多步骤处理时保留失败补偿,不把半完成记录显示成成功。

与 AI 摘要的关系

摘要只接受自己上传的纯文本或 Markdown,不支持直接把图片当文本处理。当前摘要输入最多读取前 16,000 个字符,上传允许 1 MiB 不代表模型会处理整个文件。详见 AI 与任务。

验证与排障

  • Unsupported file type or size:检查实际 MIME、零字节和大小,而不只看扩展名。
  • 配额不足:检查当前用户文件数及 storedFiles,不改客户端计数绕过服务端。
  • 列表有记录但正文不存在:核对目标 bucket 与部署资源名,并检查中断的上传/删除。
  • 401/403:检查会话、Key 状态、邮箱验证和文件归属。

运行 Workers/API 测试并增加两个账号的交叉访问检查;真实生产验收使用自己部署的 bucket,不操作公共演示的其他用户文件。

本页目录