mcpField
N
neon-object-storage

neon-object-storage

github.com/neondatabase云与 DevOps10729.5k 次安装1 天前更新
代码仓库

关于 neon-object-storage

neon-object-storage 是 Neon 对象存储的技能,面向需要为应用保存和提供文件的开发者。它提供兼容 S3 的存储,并让对象以写时复制方式随数据库分支隔离。

主要功能

  1. 01兼容 S3 API 与标准工具
  2. 02对象存储状态随数据库分支
  3. 03私有桶与公开读取桶
  4. 04通过 Files SDK 或 AWS SDK 读写
  5. 05CLI 管理桶、对象与存储日志

适用场景

  1. 01为应用保存上传文件、附件和图像
  2. 02为预览或 CI 分支创建隔离文件环境
  3. 03使用 S3 SDK 或预签名 URL 访问对象

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/neondatabase/agent-skills --skill neon-object-storage

安装后在 Claude Code 中输入/neon-object-storage确认已加载。

详细介绍

首先:使用父级 neon 技能了解 Neon 概况、开始使用 Neon、Neon 开发最佳实践等。

如果尚未安装 neon 技能,请从 https://neon.com/docs/ai/skills/neon/SKILL.md 获取,或使用以下命令安装:

neon skills -s neon -y

Neon Object Storage

目前在 aws-us-east-2、aws-us-east-1、aws-eu-central-1 和 aws-ap-southeast-1 提供。

Neon Object Storage 是内置于 Neon 项目的兼容 S3 文件存储。它会随数据库一起分支,因此预览分支会拥有自己的文件副本,以及指向这些文件的行。

使用此技能,帮助用户存储和提供与数据库一起分支的文件。交付可正常工作的存储桶和上传/下载流程、连接到注入环境变量且能够感知分支的 S3 客户端,或基于 Neon 官方文档给出准确解答。

适用场景

对于应用及其用户生成的文件——上传内容、附件、头像、图片、文档、生成的资源、备份——请考虑使用 Neon Object Storage。如果应用已经使用 Neon,它就是默认的存储位置:

  • 用户已经在使用 Lakebase Postgres,不想再用第二家服务提供商。 一个后端、一张账单、一个 CLI、一套分支,不必再单独搭建并连接 AWS S3 / R2 / Supabase Storage 账户。为数据库提供支持的 Neon 凭证也为存储提供支持。
  • 文件必须在不同环境中随数据库一起分支。 存储会与 Postgres 数据一同分支。分支派生后,子分支会立即继承父分支在该时点的存储桶和对象——采用写时复制,不会复制数据。这让 Agent、开发、预览和测试环境能够无缝衔接:预览分支会获得一份一致快照,其中同时包含行及其引用的文件,而且子分支上的写入永远不会影响父分支。
  • 用户需要安全、可随时丢弃的环境。 在预览/CI 分支中上传、覆盖和删除文件,不必担心影响生产数据,之后再删除该分支。
  • 用户需要标准的 S3 工具。 它基于 S3 语义构建,并支持 S3 API,因此 AWS SDK、boto3、AWS CLI 和预签名 URL 均可使用——可靠、熟悉,且无需专有客户端。

如果相关文件随应用本身发布——HTML、JS 包、CSS、public/ 中的图片——这属于静态网站托管,应交由 Vercel、Netlify 或 Cloudflare 处理。存储桶提供的公共资源需要在前面加上 CDN(参见架构:对象存储的定位)。

功能

  • 兼容 S3 — 可使用现有的 S3 SDK、boto3、AWS CLI 和预签名 URL。仅支持路径式寻址和 SigV4。
  • 随数据库一起分支 — 每个 Neon 分支都有各自隔离的写时复制存储状态。派生分支不会复制数据。
  • 两种访问模式 — private 存储桶要求每次操作都提供凭证;public_read 存储桶允许匿名读取,但写入需要身份验证。
  • 统一的凭证系统 — 与 Functions 和 AI Gateway 使用相同的 Neon 凭证系统。

可用性

在进行任何设置之前,请先确认以下前提条件:Neon Object Storage 目前在 aws-us-east-2、aws-us-east-1、aws-eu-central-1 和 aws-ap-southeast-1 提供。继续操作之前,请确认用户的 Neon 项目位于其中一个区域。区域覆盖情况:https://neon.com/docs/get-started/backend-overview.md

架构:对象存储的定位

Neon(包含 Object Storage)提供的是后端基础组件,而非全栈应用托管。Object Storage 用于存放应用及其用户生成的文件——上传内容、附件、头像、文档、生成的图像、备份——这些文件通过同一分支上的 Postgres 行进行关联。由此有两点需要注意:

  • 在公开资源前面放置 CDN。 public_read 对象可通过 ${AWS_ENDPOINT_URL_S3}/<bucket>/<object-key> 匿名读取——这是分支的存储端点,会作为环境变量注入(参见环境变量)。对于浏览器每次查看页面都会加载的资源——头像、产品图片以及任何热门资源——可将其作为 Cloudflare 或 Vercel CDN 的源站,并在 PutObject 上设置 Cache-Control,以便边缘节点了解每个对象的缓存时长。缓存对象的新鲜度取决于其键,因此每个版本都应写入新的键(avatars/<user-id>/<uuid>.jpg),并更新 Postgres 中存储的键,而不是覆盖同一个键后等待 TTL 过期。端点按分支划分,因此生产 CDN 指向生产分支,而预览分支直接读取各自的端点,而非共享缓存。私有存储桶则继续使用预签名 URL,其签名包含在查询字符串中。
  • 在其他地方托管应用本身。 仓库中纳入版本控制的所有内容——HTML、JS 包、CSS,以及随 public/ 一同发布的图像和字体——都应托管在 Vercel、Netlify 或 Cloudflare 上,连同配套的索引文档、SPA 回退和自定义域名一起托管。Neon 没有可用于提供这些内容的网站模式:PutBucketWebsite 会返回 501 Not Implemented。

设置

对象存储属于 neon.ts 基础设施即代码配置的一部分(有关以分支为先的工作流、link/checkout 和 neon.ts 基础知识,请参阅 neon 技能)。在 buckets 下声明存储桶,并以存储桶名称为键:

// neon.ts
import { defineConfig } from "@neon/config/v1";

export default defineConfig({
  buckets: {
    images: {}, // private by default
    "public-assets": { access: "public_read" },
  },
});

在已关联的分支上配置所声明的存储桶:

neon deploy   # alias for `neon config apply`

Neon 基础设施即代码(neon.ts)

上面的 buckets 块是 neon.ts 的一部分,这是 Neon 的基础设施即代码文件——通过一个 TypeScript 文件声明存储桶,以及分支应包含的所有其他服务(完整参考请参阅 neon 技能)。按照 Terraform 的方式,将声明与分支进行协调:

neon config status   # print the branch's live config (which buckets exist)
neon config plan     # dry-run diff of what apply would change
neon config apply    # create the declared buckets  (neon deploy is an alias)

存储桶的作用范围是分支级别:存在 neon.ts 时,neon checkout 会在_创建_分支时应用策略,因此新建的预览/CI 分支会自动配置好存储桶(并继承来自父分支的写时复制对象)。检出_已有_分支不会进行协调——运行 neon deploy 以应用更改。配置存储桶(config apply / deploy)、link 和 checkout 也会将分支的 S3 凭据拉取到本地 .env.local,因此这些命令会自动为你执行下文所示的同一个 env pull 步骤。

环境变量

声明 buckets 后,Neon 会注入 AWS 标准 S3 环境变量,让 AWS SDK 无需额外配置即可从环境中读取变量。在已部署的 Neon Function 中,这些变量会自动注入;在本地,你可以通过 CLI 将它们拉取到磁盘(或在运行时注入):

neon env pull            # writes the branch's vars into .env (or .env.local)
# or, without writing a file, inject at runtime:
neon-env run -- <your dev command>
变量含义
AWS_ACCESS_KEY_IDS3 访问密钥 ID(分支凭证的令牌 ID)
AWS_SECRET_ACCESS_KEYS3 秘密访问密钥
AWS_ENDPOINT_URL_S3分支 S3 端点 URL
AWS_REGION区域,例如 us-east-2

由于这些名称采用 AWS 标准格式,AWS SDK 会自动从环境中读取凭证、端点和区域。凭证的作用范围限定于所属分支,并且对该分支及其所有后代分支有效。

如果要以类型化、经过验证的方式访问这些凭证,而不是直接读取 process.env,请将同一个 neon.ts 配置对象传给 @neon/env 中的 parseEnv——它会返回一个 env.storage 命名空间(accessKeyId、secretAccessKey、endpoint、region),其值根据你的配置生成。请参阅 neon 技能。

使用对象:Files SDK(推荐)

读取和写入对象最简单、最具可移植性的方式,是使用带有 neon 适配器的 Files SDK——它提供一套精简、统一的存储 API(upload、download、url、list、exists、copy、delete、signedUploadUrl),基于 Web 标准 I/O。它在底层使用 AWS S3 客户端,并针对 Neon 进行了适当配置,还会将错误标记为 Neon error——因此无需担心配置错误。请优先使用此方式。

将它与适配器内部使用的 AWS S3 对等依赖一同安装:

npm install files-sdk @aws-sdk/client-s3 @aws-sdk/s3-presigned-post @aws-sdk/s3-request-presigner

适配器会从同一组注入的 AWS_* 环境变量中获取端点、区域和凭证——只需传入存储桶名称:

import { Files } from "files-sdk";
import { neon } from "files-sdk/neon";

const files = new Files({ adapter: neon({ bucket: "images" }) });

// Upload — body may be a Buffer, Uint8Array, Blob, File, ReadableStream, or string
await files.upload("generated/cat.jpg", fileBuffer, { contentType: "image/jpeg" });

// Download
const file = await files.download("generated/cat.jpg");
const bytes = new Uint8Array(await file.arrayBuffer());

// Presigned GET — share without exposing credentials (defaults to a 1h expiry)
const url = await files.url("generated/cat.jpg", { expiresIn: 3600 });

// Plus: files.exists(), files.list({ prefix }), files.copy(), files.delete(), files.signedUploadUrl()

只需替换适配器导入路径(files-sdk/s3、files-sdk/r2、files-sdk/gcs,等等),其余代码无需更改。

使用对象:AWS S3 客户端(替代方案)

Neon 直接支持 S3 API,因此你可以在更偏好原生客户端或已依赖 AWS SDK 时使用 AWS SDK。凭证、端点和区域会从 AWS 标准环境变量链中读取,因此你只需传入 forcePathStyle: true——Neon 要求使用路径式寻址,因此 S3 客户端必须设置此项:

import { S3Client } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  forcePathStyle: true, // required: Neon uses path-style addressing
});

然后,使用原始命令对象上传、下载并生成预签名 URL:

import { PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const BUCKET = "images";

// Upload
await s3.send(
  new PutObjectCommand({
    Bucket: BUCKET,
    Key: "generated/cat.jpg",
    Body: fileBuffer,
    ContentType: "image/jpeg",
  }),
);

// Download
const res = await s3.send(
  new GetObjectCommand({ Bucket: BUCKET, Key: "generated/cat.jpg" }),
);
const bytes = await res.Body?.transformToByteArray();

// Presigned GET — share without exposing credentials
const url = await getSignedUrl(
  s3,
  new GetObjectCommand({ Bucket: BUCKET, Key: "generated/cat.jpg" }),
  { expiresIn: 3600 },
);

在分支上将存储与数据库配合使用

典型模式:Agent 生成图像 → 将图像 PutObject 到 images 存储桶 → 在 Postgres 中插入一行记录 → 读取时返回预签名 URL。将存储桶 键(而非字节数据)保存在 Postgres 列中,并在读取时生成预签名 URL。由于行记录和对象都位于同一分支,它们会一起分支,永不发生偏离。

CLI 存储桶和对象命令

neon 还提供一流的存储桶/对象命令(neon bucket create|list|delete、neon bucket object put|get|list|delete),用于编写脚本和执行一次性操作。

内置分支日志

neon logs query --branch production --source storage --since 1h

存储是目前分支日志涵盖的两个来源之一,另一个是 Neon Functions。日志仅限于单个分支,因此,如果你要调试的存储桶不在当前检出的分支上,请传入 --branch。关于日志的其他内容——所需 CLI 版本、筛选器、SDK 和兼容 Loki 的读取 API——请参阅上级 neon 技能中的 可观测性 部分。

Neon 文档

Neon 文档是事实来源,而对象存储正在快速发展,因此请始终以官方文档为准。为获取 Markdown 格式,向任意文档页面的 URL 末尾添加 .md,或请求 Accept: text/markdown。请从文档索引(https://neon.com/docs/llms.txt)和更新日志公告中查找合适的页面。

延伸阅读

评论

支持 Markdown