尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

InsForge Storage SDK 实战指南:用一行 `createClient` 完成对象存储的上传、下载与删除

InsForge Storage SDK 实战指南:用一行 `createClient` 完成对象存储的上传、下载与删除 InsForge Storage SDK 实战指南用一行createClient完成对象存储的上传、下载与删除【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForgeInsForge 是一个开源的 all-in-one 后端平台内置的对象存储Storage模块为你的应用提供 Bucket 管理、文件上传、下载、删除、列表与公开 URL 生成能力。本文以仓库存档文档.archive/docs/deprecated/insforge-storage-sdk.md为核心结合当前仓库后端源码系统讲解 InsForge Storage SDK 的完整用法从客户端初始化、Bucket 与文件操作到浏览器端上传/展示图片、错误处理的最佳实践。读完本文你将能直接在项目里接入 InsForge 对象存储并理解每个 SDK 调用在服务端对应的 REST 路由与权限行为。快速开始初始化客户端Storage SDK 是 InsForge TypeScript SDKinsforge/sdk的存储子模块。第一步是创建客户端实例并指定后端地址import { createClient } from insforge/sdk; const client createClient({ baseUrl: http://localhost:7130 });baseUrl指向 InsForge 后端的对外地址。本地开发默认端口为7130见示例中的http://localhost:7130部署后请替换为你的实际域名或 IP。初始化后通过client.storage访问存储能力与数据库、认证等模块一样它是 SDK 中一个独立的能力域。核心概念Bucket 与 Object Key在进入 API 之前先明确两个贯穿全文的概念与 S3 的对象存储模型一致Bucket存储桶对象的命名空间容器分为**公开桶public与私有桶private**两类。公开桶允许未认证的下载私有桶的所有操作都需要认证。Object Key对象键对象在桶内的唯一标识支持路径形式如folder/subfolder/file.jpg。在服务端StorageService.validateKey会拒绝包含..目录穿越或以/开头的 key见 storage.service.ts。from(bucketName)选择操作目标所有文件操作都从选定一个 Bucket 开始const bucket client.storage.from(avatars); // Returns StorageBucket instancefrom(avatars)返回一个StorageBucket实例后续的upload、download、remove、list、getPublicUrl都通过它调用。值得注意的是Bucket 的创建与删除由管理端完成源码中为verifyAdmin保护的管理接口SDK 不负责建桶/删桶——原文档的 Notes 一节对此有明确说明。文件操作 API 详解upload按指定 Key 上传// Upload with specific key const { data, error } await client.storage .from(avatars) .upload(user-123.jpg, file); // data: StorageFileSchema { bucket, key, size, mimeType, uploadedAt, url }返回的data遵循StorageFileSchema其字段定义在仓库的 storage.schema.ts 中字段类型说明keystring对象键bucketstring所属桶名sizenumber字节大小mimeTypestring可选MIME 类型uploadedAtstring上传时间ISO 字符串urlstring可访问的下载 URL服务端实现中upload对应PUT /api/storage/buckets/:bucketName/objects/*路由语义是在精确 Key 上创建或替换对象标准 PUT 语义覆盖已有对象SDK 内部负责构造 multipart/form-data 请求见 index.routes.ts 中的dynamicUploadSingle(file)中间件与putObject的INSERT ... ON CONFLICT DO UPDATE。uploadAuto自动生成唯一 Key// Upload with auto-generated key const { data, error } await client.storage .from(avatars) .uploadAuto(file); // Generated key format: filename-timestamp-random.extuploadAuto让服务端为你生成不会冲突的 Key对应POST /api/storage/buckets/:bucketName/objects路由。服务端StorageService.generateObjectKey的实现storage.service.ts为generateObjectKey(originalFilename: string): string { const timestamp Date.now(); const randomStr Math.random().toString(36).substring(2, 8); const fileExt originalFilename ? path.extname(originalFilename) : ; const baseName originalFilename ? path.basename(originalFilename, fileExt) : file; const sanitizedBaseName baseName.replace(/[^a-zA-Z0-9-_]/g, -).substring(0, 32); const objectKey ${sanitizedBaseName}-${timestamp}-${randomStr}${fileExt}; return objectKey; }可以看到 Key 由三部分组成清洗后的文件名最长 32 字符非法字符替换为-、毫秒级时间戳、6 位随机字符串最后拼接原始扩展名。这正是原文档所说filename-timestamp-random.ext格式的精确来源。当多个用户并发上传同名文件时uploadAuto可从根本上避免 Key 冲突这也是原文档 Notes 中UseuploadAuto()to prevent filename conflicts的原因。download下载对象为 Blobconst { data: blob, error } await client.storage .from(avatars) .download(user-123.jpg); // data: Blob (can convert to URL with URL.createObjectURL(blob))download返回浏览器Blob对象配合URL.createObjectURL(blob)可以直接用于img、video或a download等场景。服务端对应GET /api/storage/buckets/:bucketName/objects/*路由公开桶直接放行conditionalDownloadAuth中间件跳过认证私有桶要求 JWT 或 API Key 认证。remove删除对象const { data, error } await client.storage .from(avatars) .remove(user-123.jpg);对应服务端DELETE /api/storage/buckets/:bucketName/objects/*路由。服务端还支持批量删除DELETE /objects一次最多 1000 个 Key见deleteObjectsRequestSchema约束并会先删除数据库元数据行、再清理底层存储S3/本地文件对每个 Key 返回deleted/notFound/failed三种状态。list列出对象支持前缀过滤与分页const { data, error } await client.storage .from(avatars) .list({ prefix: users/, // Filter by prefix search: profile, // Search in filenames limit: 10, // Max results (default: 100) offset: 0 // Skip results }); // data: ListObjectsResponseSchema { bucketName, objects[], pagination }list对应服务端GET /api/storage/buckets/:bucketName/objects路由其行为可以在服务端源码中精确验证prefix按前缀过滤服务端执行key LIKE escapedPrefix%escapeSqlLikePattern会先转义%与_通配符防 SQL 注入。search在文件名中做子串匹配服务端执行key LIKE %escapedQuery%。limit默认 100服务端将入参钳制在[1, 1000]区间Math.min(Math.max(1, limit), 1000)。offset跳过前 N 条服务端保证不小于 0。响应的pagination结构定义在 storage-api.schema.ts 的listObjectsResponseSchema中包含offset、limit、total三个字段total由服务端COUNT(*)查询返回便于前端实现加载更多或分页组件。注意当前 schema 的顶层字段实际为data对象数组与pagination原文档中bucketName为早期版本形态以仓库 schema 为准。getPublicUrl零请求生成公开 URL// Get public URL (no API call) const url client.storage .from(avatars) .getPublicUrl(user-123.jpg); // Returns: http://localhost:7130/api/storage/buckets/avatars/objects/user-123.jpggetPublicUrl是纯本地拼接不发起任何网络请求因此适合公开桶对象的直接引用。其 URL 模式与服务端StorageService.buildObjectUrl保持一致const base ${getApiBaseUrl()}/api/storage/buckets/${bucket}/objects/${encodeURIComponent(key)};服务端在返回StorageFileSchema时会追加?vversion缓存失效参数基于 etag回退到uploaded_atCDN 按完整 URL 缓存时可实现覆盖上传后立即看到新内容无需调用失效 API。但手动调用getPublicUrl得到的裸 URL 不携带版本戳覆盖上传后若命中 CDN 缓存可能看到旧版本。上传实战三种典型场景从input typefile上传// HTML: input typefile idfileInput const fileInput document.getElementById(fileInput); const file fileInput.files[0]; const { data, error } await client.storage .from(uploads) .upload(photos/${file.name}, file);利用 Key 支持路径的特性可以很方便地把上传文件归入photos/子目录。上传 Blobconst blob new Blob([Hello World], { type: text/plain }); const { data, error } await client.storage .from(documents) .upload(hello.txt, blob);服务端会校验并规范化 MIME 类型路由中的enforceSafeMimeType会读取文件魔数magic bytes来覆盖客户端上报的mimetype对于可执行类型HTML、SVG、JS统一归一化为application/octet-stream避免存储可被浏览器直接执行的资源详见 mime-guard.ts 与路由中的isUnsafeMime/resolveSafeMimeType。使用自定义文件名// Simple file upload - SDK handles FormData creation const file fileInput.files[0]; const { data, error } await client.storage .from(uploads) .upload(custom-name.jpg, file);SDK 负责 FormData 的构造你只需要提供目标 Key 与文件对象。下载与展示浏览器中的正确姿势下载并显示图片const { data: blob, error } await client.storage .from(avatars) .download(user-123.jpg); if (blob) { const url URL.createObjectURL(blob); document.getElementById(avatar).src url; // Clean up URL.revokeObjectURL(url); }要点用完createObjectURL生成的 URL 后调用URL.revokeObjectURL(url)释放内存避免长页面/频繁切换头像时内存泄漏。公开桶直接使用 URL// For public buckets, use direct URL const url client.storage .from(public-avatars) .getPublicUrl(user-123.jpg); document.getElementById(avatar).src url;对于公开桶直接用getPublicUrl得到的 URL 赋给src即可浏览器无需认证即可加载——服务端的conditionalDownloadAuth中间件在检测到公开桶时会跳过verifyUser认证index.routes.ts。错误处理模式SDK 的所有操作都返回{ data, error }解构形式建议始终检查errorconst { data, error } await client.storage .from(avatars) .upload(user-123.jpg, file); if (error) { if (error.statusCode 409) { console.error(File already exists); } else if (error.statusCode 404) { console.error(Bucket not found); } else { console.error(error.message); } }这两个状态码在服务端有明确对应逻辑409 Conflict对象已存在putObject遇到主键冲突时PostgreSQL 错误码23505路由将其映射为409 STORAGE_ALREADY_EXISTS见 index.routes.ts 的mapObjectWriteError。注意upload使用PUT语义上传到已存在 Key 时会覆盖409 主要出现在并发写入或唯一性约束冲突场景。404 Not Found桶不存在POST /objects上传到不存在的桶时服务端返回404 STORAGE_NOT_FOUND错误信息会提示Create the bucket first using POST /api/storage/buckets。其他错误通过error.message携带具体原因例如 key 非法包含..或以/开头返回 400、RLS 权限不足返回 403STORAGE_PERMISSION_DENIED、超过配置的最大上传大小返回 413服务端confirmUpload会以配置的maxFileSizeMb钳制默认上限见 storage-config.service.ts。权限模型与注意事项原文档 Notes 中列出的行为在服务端均有对应实现这里汇总成一张速查表规则服务端实现依据Bucket 创建/删除由管理端完成SDK 不负责POST /buckets、DELETE /buckets均挂verifyAdmin中间件index.routes.ts公开桶允许未认证下载conditionalDownloadAuth对公开桶跳过verifyUser私有桶所有操作需要认证其余路径统一走verifyUser且对象级可见性由storage.objects表的 RLS 策略控制Key 支持路径形式list的prefix、上传时的folder/subfolder/file.jpg均由 Key 的LIKE匹配实现用uploadAuto()避免文件名冲突generateObjectKey追加timestamp-random后缀见上文源码补充几点实战提醒可见性与 RLS普通终端用户JWT对私有桶对象的访问受行级安全RLS策略约束storage.objects的默认策略按uploaded_by归属控制可见性API Key 与项目管理员走后端池绕过 RLS。若你的应用需要多人共享同一对象需要在数据库中调整相应的 SELECT 策略。不安全 MIME 强制下载即使某个对象存储了text/html等不安全 MIME服务端在响应时会强制加Content-Disposition: attachment与X-Content-Type-Options: nosniff浏览器只会下载而不会内联渲染这是服务端的纵深防御路由中isUnsafeMime判断。下载策略与预签名 URLSDK 的download在服务端可能被实现为直接转发或重定向到预签名 URLgetDownloadStrategy返回presigned/direct两种策略。私有桶的预签名 URL 有效期默认 1 小时PRIVATE_BUCKET_EXPIRY 3600秒公开桶不过期且支持通过expiresIn参数自定义钳制在 1 秒到 7 天之间。对象大小限制上传大小受存储配置maxFileSizeMb约束1–200 MB见updateStorageConfigRequestSchema超过会收到 413 错误。以上 API 行为均有对应的单元测试覆盖例如 storage-routes.test.ts 验证了 Bucket 创建、对象 CRUD 与错误码映射底层存储支持本地文件系统与 S3 两种 ProviderLocalStorageProvider/S3StorageProvider在 storage.provider 下因此同一套 SDK 接口在自托管与云环境间无缝切换。掌握本文的 SDK 用法与权限模型你就能在 InsForge 上快速落地文件上传、头像、附件、媒体库等典型存储场景。【免费下载链接】InsForgeThe all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.项目地址: https://gitcode.com/GitHub_Trending/in/InsForge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表