ZS3 坐标
0 运行时间依赖性 ^ 只 ~ 3 KB 已修改 ^ 在 Web 平台 API 上构建
ZS3正在积极开发中;公共API可能会演化.
概览
ZS3 坐标 是JavaScript和TypeScript的轻量级S3兼容客户端. 仅限 ~3 KB 已修改,它会签署 AWS 签名版本 4 请求,并通过标准 Web 平台 API 等与对象存储通信 fetch, (中文(简体) ), Response, (中文(简体) ), TextEncoder,以及 crypto.subtle。 。 。 .
使用 exec() 签署和发出请求,或 sign() 创建预先签名的 URL , 并定期发送 fetch()土著 Response 对象可以方便地流出下载,检查信头,并与网络框架相融合.
ZeroS3目标 Node.js, Bun, 浏览器, 以及 Cloudflare 工人等边缘运行时间,只要有所需的网络API.
特征
从包脚印和平台基础订购到S3能力:
- 只有~3 KB 已修改 ——用于性能敏感应用的紧凑客户端.
- 零依赖关系 ——建于原生的Web API上,没有SDK依赖树.
- 类型脚本 ——打出配置,请求选项,客户端方法,以及S3响应形状. 公共类型:
@focus-at/zs3/types。 。 。 . - 网络平台 API - 用途
fetch, (中文(简体) ),Response, (中文(简体) ),TextEncoder,以及crypto.subtle。 。 。 . - 节点.js、 Bun、 浏览器和边缘运行时间 ——包括Cloudflare Workers,那里有所需的网络API.
- S3 兼容 API ——用于桶操作,对象上市和平面图,对象CRUD,元数据,标记,和S3子资源的一致请求模型.
- AWS 签名版本 4 ——签署直接请求或生成预先签名的URL.
快速启动
npm install @focus-at/zs3
在信任的服务器环境中生成一个短命的 URL, 然后让浏览器按照标准发送请求 fetch(),在服务器上保留永久证书;从不披露浏览器代码中的秘密访问密钥.
// Server: create a pre-signed URL.
import { zs3 } from "@focus-at/zs3";
const signer = zs3({
endpoint: process.env.S3_ENDPOINT!,
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
region: "us-east-1",
});
const url = await signer.sign(
{ method: "GET", bucket: "my-bucket", key: "reports/annual.pdf" },
{ expiresIn: 300 },
);
// Browser: use the URL with the standard Fetch API.
const response = await fetch(url);
console.log(response.status, await response.blob());
对于直接服务器侧请求, exec() 签名并发送请求并返回本地 Response数字 :
import { zs3 } from "@focus-at/zs3";
import type { ZS3Objects } from "@focus-at/zs3/types";
const client = zs3({
endpoint: process.env.S3_ENDPOINT!,
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
bucket: "my-bucket",
});
const response = await client.exec<ZS3Objects>({ method: "GET", prefix: "reports/" });
const { key, data } = await response.json();
console.log(data);
自定义用户系统平滑
import { zs3, handler } from 'zs3-sdk';
const s3 = zs3({
handler: async (res: Response) => {
const { key, data } = await handler(res);
return data; // Manual flattening on the user side if they don't need the root key
}
});
有用的操作模式
按页列出对象
使用 fetch-owner 将所有者信息列入清单。 下一页,通过 NextContinuationToken 作为 continuation-token 查询参数.
import type { ZS3Objects } from "@focus-at/zs3/types";
const firstResponse = await client.exec<ZS3Objects>(
{ method: "GET", prefix: "reports/" },
{ query: { delimiter: "/", "max-keys": 100, "fetch-owner": true } },
);
const { data: firstPage } = await firstResponse.json();
if (firstPage.IsTruncated && firstPage.NextContinuationToken) {
const nextResponse = await client.exec<ZS3Objects>(
{ method: "GET", prefix: "reports/" },
{
query: {
delimiter: "/",
"max-keys": 100,
"fetch-owner": true,
"continuation-token": firstPage.NextContinuationToken,
},
},
);
const { data: nextPage } =await nextResponse.json();
console.log(nextPage);
}
处理对象版本
启用带有桶的版本 versioning 分资源。 然后列出版本并使用返回的版本 VersionId 以请求特定对象版本.
await client.exec(
{ method: "PUT", bucket: "my-bucket", key: "" },
{
query: { versioning: "" },
headers: { "Content-Type": "application/xml" },
body: "<VersioningConfiguration><Status>Enabled</Status></VersioningConfiguration>",
},
);
const versionsResponse = await client.exec(
{ method: "GET", bucket: "my-bucket", key: "" },
{ query: { versions: "", prefix: "reports/" } },
);
const { data } = await versionsResponse.json();
// Use a VersionId returned by the version listing.
const objectVersion = await client.exec(
{ method: "GET", bucket: "my-bucket", key: "reports/annual.pdf" },
{ query: { versionId: "VERSION_ID" } },
);
设定对象元数据和标签
上传时发送用户元数据 x-amz-meta-* 头并可用 HEAD标记通过 tagging 分资源.
await client.exec(
{ method: "PUT", key: "reports/annual.pdf", body: file },
{
headers: {
"Content-Type": "application/pdf",
"x-amz-meta-source": "finance",
},
},
);
const metadata = await client.exec({ method: "HEAD", key: "reports/annual.pdf" });
console.log(metadata.headers.get("x-amz-meta-source"));
await client.exec(
{ method: "PUT", key: "reports/annual.pdf", body: taggingXml },
{
query: { tagging: "" },
headers: { "Content-Type": "application/xml" },
},
);
检查或更改对象的ACL,使用单独的 acl 子资源 :
const acl = await client.exec(
{ method: "GET", key: "reports/annual.pdf" },
{ query: { acl: "" } },
);
发送自定义请求
使用带有查询参数、信头和正文的自定义路径——例如,调用应用程序特定端点:
const response = await adminClient.exec(
{
method: "PUT",
key: "admin/v3/add-user",
body: JSON.stringify({ accessKey, status: "enabled" }),
},
{
query: { source: "dashboard" },
headers: { "Content-Type": "application/json" },
},
);
见 examples/custom-request.ts 对于完整的例子.
将一个大对象按部件上传
多段上传被分成请求启动上传,发送每个部分,并完成. 留着 uploadId 和每个上传部分的ETag用于完成请求.
const initiated = await client.exec(
{ method: "POST", key: "archives/backup.zip" },
{ query: { uploads: "" } },
);
const { data: { UploadId } } = await initiated.json();
const partResponse = await client.exec(
{ method: "PUT", key: "archives/backup.zip", body: part },
{ query: { uploadId: UploadId, partNumber: 1 } },
);
const etag = partResponse.headers.get("etag");
const partsXml = `<CompleteMultipartUpload>
<Part><PartNumber>1</PartNumber><ETag>${etag}</ETag></Part>
</CompleteMultipartUpload>`;
await client.exec(
{ method: "POST", key: "archives/backup.zip", body: partsXml },
{
query: { uploadId: UploadId },
headers: { "Content-Type": "application/xml" },
},
);
关于列出部件和中止上传,请参见 examples/multipart.ts。 。 。 .
API 覆盖图
| 区域 | 涵盖的情况 |
|---|---|
| 签名 | AWS4 签名, 预先签名的 URL, 标准 fetch 签署后 |
| 弹夹 | 列表/创建/删除; ACL, 版本化, 生命周期, 策略, 标签, CORS, 加密, 网站, 通知, 日志化, 复制, 公共访问块, 对象锁定 |
| 对象列表 | 前缀、 分隔符、 最大键、 起步键、 取取所有者、 接续键页 |
| 对象 | Get, PUT, Head, DELETE, ACL, 标记, 用户元数据, 属性, 恢复, 保留/ 法律控件, 对象版本( 列表/ get/ 删除) |
| 多块 | 启动、上传部分、列表部分、完整、中止 |
| 自定义请求 | 自定义路径、 查询参数、 页眉、 正文 |
| 错误 | 状态处理和解析 S3 XML 出错有效载荷 |
实例
这个 examples/ 目录载有按工作流程分类的完整实例:
presigned-fetch.ts——在服务器上创建一个预先签名的URL,并以标准发送请求fetch()。 。 。 .custom-request.ts——自定义端点路径有查询参数,头,和一个请求正文.buckets.ts——列表,创建,并删除桶;ACL,版本,生命周期,政策,标签,CORS,加密,网站,通知,日志,复制,公众访问,以及对象锁定.objects.ts- 列出和标出物体;prefix, (中文(简体) ),delimiter, (中文(简体) ),fetch-owner,从起始键列表, CRUD, ACL, 标记, 元数据, 副本, 属性, 恢复, 保留, 合法控件, 和列表/get/删除对象版本 .multipart.ts——启动,上传部分,列出部分,完成,并中止多段上传.
例子使用占位符证书和终点。 调整时提供自己的配置; 避免运行破坏性操作, 如桶或对象删除 .