Skip to content

生產服務器通常從本地文件系統讀取、上傳和寫入文件到 S3 兼容的對象存儲服務,而不是本地文件系統。歷史上,這意味著你在開發中使用的本地文件系統 API 不能在生產中使用。當你使用 Bun 時,情況就不同了。

Bun 的 S3 API 很快

Bun 提供快速、原生的綁定用於與 S3 兼容的對象存儲服務交互。Bun 的 S3 API 設計簡單,感覺類似於 fetch 的 ResponseBlob API(就像 Bun 的本地文件系統 API 一樣)。

ts
import { s3, write, S3Client } from "bun";

// Bun.s3 讀取環境變量的憑證
// file() 返回 S3 上文件的惰性引用
const metadata = s3.file("123.json");

// 從 S3 下載為 JSON
const data = await metadata.json();

// 上傳到 S3
await write(metadata, JSON.stringify({ name: "John", age: 30 }));

// 預簽名 URL(同步 - 不需要網絡請求)
const url = metadata.presign({
  acl: "public-read",
  expiresIn: 60 * 60 * 24, // 1 天
});

// 刪除文件
await metadata.delete();

S3 是 事實標准 的互聯網文件系統。Bun 的 S3 API 適用於 S3 兼容存儲服務,如:

  • AWS S3
  • Cloudflare R2
  • DigitalOcean Spaces
  • MinIO
  • Backblaze B2
  • ...以及任何其他 S3 兼容存儲服務

基本用法

有幾種方法可以與 Bun 的 S3 API 交互。

Bun.S3ClientBun.s3

Bun.s3 等同於 new Bun.S3Client(),依賴環境變量獲取憑證。

要顯式設置憑證,將它們傳遞給 Bun.S3Client 構造函數。

ts
import { S3Client } from "bun";

const client = new S3Client({
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // sessionToken: "..."
  // acl: "public-read",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
  // endpoint: "https://<region>.digitaloceanspaces.com", // DigitalOcean Spaces
  // endpoint: "http://localhost:9000", // MinIO
});

// Bun.s3 是全局單例,等同於 `new Bun.S3Client()`

使用 S3 文件

S3Client 中的 file 方法返回 S3 上文件的惰性引用

ts
// S3 上文件的惰性引用
const s3file: S3File = client.file("123.json");

Bun.file(path) 一樣,S3Clientfile 方法是同步的。在調用依賴網絡請求的方法之前,它不會進行任何網絡請求。

從 S3 讀取文件

如果你使用過 fetch API,你熟悉 ResponseBlob API。S3File 擴展了 Blob。適用於 Blob 的方法也適用於 S3File

ts
// 將 S3File 讀取為文本
const text = await s3file.text();

// 將 S3File 讀取為 JSON
const json = await s3file.json();

// 將 S3File 讀取為 ArrayBuffer
const buffer = await s3file.arrayBuffer();

// 僅獲取前 1024 字節
const partial = await s3file.slice(0, 1024).text();

// 流式讀取文件
const stream = s3file.stream();
for await (const chunk of stream) {
  console.log(chunk);
}

內存優化

text()json()bytes()arrayBuffer() 這樣的方法在可能時避免在內存中復制字符串或字節。

如果文本恰好是 ASCII,Bun 直接將字符串傳輸到 JavaScriptCore(引擎)而無需轉碼且在內存中不復制字符串。當你使用 .bytes().arrayBuffer() 時,它也會避免在內存中復制字節。

這些輔助方法不僅簡化了 API,還使其更快。

寫入和上傳文件到 S3

寫入 S3 同樣簡單。

ts
// 寫入字符串(替換文件)
await s3file.write("Hello World!");

// 寫入 Buffer(替換文件)
await s3file.write(Buffer.from("Hello World!"));

// 寫入 Response(替換文件)
await s3file.write(new Response("Hello World!"));

// 寫入並指定內容類型
await s3file.write(JSON.stringify({ name: "John", age: 30 }), {
  type: "application/json",
});

// 使用寫入器(流式)
const writer = s3file.writer({ type: "application/json" });
writer.write("Hello");
writer.write(" World!");
await writer.end();

// 使用 Bun.write 寫入
await Bun.write(s3file, "Hello World!");

處理大文件(流)

Bun 自動處理大文件的多部分上傳並提供流式功能。適用於本地文件的 API 也適用於 S3 文件。

ts
// 寫入大文件
const bigFile = Buffer.alloc(10 * 1024 * 1024); // 10MB
const writer = s3file.writer({
  // 網絡錯誤時自動重試最多 3 次
  retry: 3,

  // 一次排隊最多 10 個請求
  queueSize: 10,

  // 以 5 MB 塊上傳
  partSize: 5 * 1024 * 1024,
});
for (let i = 0; i < 10; i++) {
  writer.write(bigFile);
  await writer.flush();
}
await writer.end();

預簽名 URL

當你的生產服務需要讓用戶上傳文件到你的服務器時,讓用戶直接上傳到 S3 通常比你的服務器作為中介更可靠。

為了促進這一點,你可以為 S3 文件預簽名 URL。這會生成一個帶簽名的 URL,允許用戶安全地將該特定文件上傳到 S3,而無需暴露你的憑證或授予他們對你的存儲桶的不必要訪問權限。

默認行為是生成一個 GET URL,在 24 小時後過期。Bun 嘗試從文件擴展名推斷內容類型。如果無法推斷,則默認為 application/octet-stream

ts
import { s3 } from "bun";

// 生成 24 小時後過期的預簽名 URL(默認)
const download = s3.presign("my-file.txt"); // GET, text/plain, 24 小時後過期

const upload = s3.presign("my-file", {
  expiresIn: 3600, // 1 小時
  method: "PUT",
  type: "application/json", // 沒有擴展名用於推斷,所以我們可以指定內容類型為 JSON
});

// 你可以在文件引用上調用 .presign(),但避免這樣做
// 除非你已經有引用(以避免內存使用)。
const myFile = s3.file("my-file.txt");
const presignedFile = myFile.presign({
  expiresIn: 3600, // 1 小時
});

設置 ACL

要在預簽名 URL 上設置 ACL(訪問控制列表),傳遞 acl 選項:

ts
const url = s3file.presign({
  acl: "public-read",
  expiresIn: 3600,
});

你可以傳遞以下任何 ACL:

ACL說明
"public-read"對象可由公眾讀取。
"private"對象僅可由存儲桶所有者讀取。
"public-read-write"對象可由公眾讀取和寫入。
"authenticated-read"對象可由存儲桶所有者和經過身份驗證的用戶讀取。
"aws-exec-read"對象可由發出請求的 AWS 賬戶讀取。
"bucket-owner-read"對象可由存儲桶所有者讀取。
"bucket-owner-full-control"對象可由存儲桶所有者讀取和寫入。
"log-delivery-write"對象可由用於日志交付的 AWS 服務寫入。

過期 URL

要為預簽名 URL 設置過期時間,傳遞 expiresIn 選項。

ts
const url = s3file.presign({
  // 秒
  expiresIn: 3600, // 1 小時

  // 訪問控制列表
  acl: "public-read",

  // HTTP 方法
  method: "PUT",
});

method

要為預簽名 URL 設置 HTTP 方法,傳遞 method 選項。

ts
const url = s3file.presign({
  method: "PUT",
  // method: "DELETE",
  // method: "GET",
  // method: "HEAD",
  // method: "POST",
  // method: "PUT",
});

new Response(S3File)

要快速將用戶重定向到 S3 文件的預簽名 URL,將 S3File 實例作為主體傳遞給 Response 對象。

這將自動將用戶重定向到 S3 文件的預簽名 URL,為你節省將文件下載到服務器並發送回用戶的內存、時間和帶寬成本。

ts
const response = new Response(s3file);
console.log(response);
txt
Response (0 KB) {
  ok: false,
  url: "",
  status: 302,
  statusText: "",
  headers: Headers {
    "location": "https://<account-id>.r2.cloudflarestorage.com/...",
  },
  redirected: true,
  bodyUsed: false
}

支持 S3 兼容服務

Bun 的 S3 實現適用於任何 S3 兼容存儲服務。只需指定適當的端點:

將 Bun 的 S3Client 與 AWS S3 一起使用

AWS S3 是默認選項。對於 AWS S3,你也可以傳遞 region 選項而不是 endpoint 選項。

ts
import { S3Client } from "bun";

// AWS S3
const s3 = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // region: "us-east-1",
});

將 Bun 的 S3Client 與 Google Cloud Storage 一起使用

要將 Bun 的 S3 客戶端與 Google Cloud Storage 一起使用,在 S3Client 構造函數中將 endpoint 設置為 "https://storage.googleapis.com"

ts
import { S3Client } from "bun";

// Google Cloud Storage
const gcs = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  endpoint: "https://storage.googleapis.com",
});

將 Bun 的 S3Client 與 Cloudflare R2 一起使用

要將 Bun 的 S3 客戶端與 Cloudflare R2 一起使用,在 S3Client 構造函數中將 endpoint 設置為 R2 端點。R2 端點包括你的賬戶 ID。

ts
import { S3Client } from "bun";

// CloudFlare R2
const r2 = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  endpoint: "https://<account-id>.r2.cloudflarestorage.com",
});

將 Bun 的 S3Client 與 DigitalOcean Spaces 一起使用

要將 Bun 的 S3 客戶端與 DigitalOcean Spaces 一起使用,在 S3Client 構造函數中將 endpoint 設置為 DigitalOcean Spaces 端點。

ts
import { S3Client } from "bun";

const spaces = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  // region: "nyc3",
  endpoint: "https://<region>.digitaloceanspaces.com",
});

將 Bun 的 S3Client 與 MinIO 一起使用

要將 Bun 的 S3 客戶端與 MinIO 一起使用,在 S3Client 構造函數中將 endpoint 設置為 MinIO 運行的 URL。

ts
import { S3Client } from "bun";

const minio = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",

  // 確保使用正確的端點 URL
  // 在生產環境中可能不是 localhost!
  endpoint: "http://localhost:9000",
});

將 Bun 的 S3Client 與 supabase 一起使用

要將 Bun 的 S3 客戶端與 supabase 一起使用,在 S3Client 構造函數中將 endpoint 設置為 supabase 端點。supabase 端點包括你的賬戶 ID 和 /storage/v1/s3 路徑。確保在 supabase 儀表板中的 https://supabase.com/dashboard/project/<account-id>/settings/storage 上啟用通過 S3 協議連接,並在同一部分設置區域。

ts
import { S3Client } from "bun";

const supabase = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  region: "us-west-1",
  endpoint: "https://<account-id>.supabase.co/storage/v1/s3/storage",
});

將 Bun 的 S3Client 與 S3 虛擬主機風格端點一起使用

使用 S3 虛擬主機風格端點時,你需要將 virtualHostedStyle 選項設置為 true

NOTE

- 如果你不指定端點,Bun 將自動使用提供的區域和存儲桶確定 AWS S3 端點。 - 如果未指定區域,Bun 默認為 us-east-1。 - 如果你顯式提供端點,則不需要指定存儲桶名稱。
ts
import { S3Client } from "bun";

// 從區域和存儲桶推斷 AWS S3 端點
const s3 = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  bucket: "my-bucket",
  virtualHostedStyle: true, 
  // endpoint: "https://my-bucket.s3.us-east-1.amazonaws.com",
  // region: "us-east-1",
});

// AWS S3
const s3WithEndpoint = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  endpoint: "https://<bucket-name>.s3.<region>.amazonaws.com",
  virtualHostedStyle: true, 
});

// Cloudflare R2
const r2WithEndpoint = new S3Client({
  accessKeyId: "access-key",
  secretAccessKey: "secret-key",
  endpoint: "https://<bucket-name>.<account-id>.r2.cloudflarestorage.com",
  virtualHostedStyle: true, 
});

憑證

憑證是使用 S3 最困難的部分之一,我們已盡力使其盡可能簡單。默認情況下,Bun 從以下環境變量讀取憑證。

選項名稱環境變量
accessKeyIdS3_ACCESS_KEY_ID
secretAccessKeyS3_SECRET_ACCESS_KEY
regionS3_REGION
endpointS3_ENDPOINT
bucketS3_BUCKET
sessionTokenS3_SESSION_TOKEN

如果 S3_* 環境變量未設置,Bun 還將檢查上述每個選項的 AWS_* 環境變量。

選項名稱回退環境變量
accessKeyIdAWS_ACCESS_KEY_ID
secretAccessKeyAWS_SECRET_ACCESS_KEY
regionAWS_REGION
endpointAWS_ENDPOINT
bucketAWS_BUCKET
sessionTokenAWS_SESSION_TOKEN

這些環境變量在初始化時從 .env 文件 或進程環境中讀取(process.env 不用於此)。

這些默認值會被你傳遞給 s3.file(credentials)new Bun.S3Client(credentials) 或任何接受憑證的方法的選項覆蓋。因此,例如,如果你為不同的存儲桶使用相同的憑證,你可以在 .env 文件中設置一次憑證,然後傳遞 bucket: "my-bucket"s3.file() 函數而無需再次指定所有憑證。

S3Client 對象

當你不使用環境變量或使用多個存儲桶時,你可以創建 S3Client 對象來顯式設置憑證。

ts
import { S3Client } from "bun";

const client = new S3Client({
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // sessionToken: "..."
  endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
  // endpoint: "http://localhost:9000", // MinIO
});

// 使用 Response 寫入
await file.write(new Response("Hello World!"));

// 預簽名 URL
const url = file.presign({
  expiresIn: 60 * 60 * 24, // 1 天
  acl: "public-read",
});

// 刪除文件
await file.delete();

S3Client.prototype.write

要將文件上傳或寫入 S3,在 S3Client 實例上調用 write

ts
const client = new Bun.S3Client({
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  endpoint: "https://s3.us-east-1.amazonaws.com",
  bucket: "my-bucket",
});

await client.write("my-file.txt", "Hello World!");
await client.write("my-file.txt", new Response("Hello World!"));

// 等同於
// await client.file("my-file.txt").write("Hello World!");

S3Client.prototype.delete

要從 S3 刪除文件,在 S3Client 實例上調用 delete

ts
const client = new Bun.S3Client({
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
});

await client.delete("my-file.txt");
// 等同於
// await client.file("my-file.txt").delete();

S3Client.prototype.exists

要檢查文件是否存在於 S3 中,在 S3Client 實例上調用 exists

ts
const client = new Bun.S3Client({
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
});

const exists = await client.exists("my-file.txt");
// 等同於
// const exists = await client.file("my-file.txt").exists();

S3File

S3File 實例通過調用 S3Client 實例方法或 s3.file() 函數創建。像 Bun.file() 一樣,S3File 實例是惰性的。它們不一定指創建時存在的東西。這就是為什麼所有不涉及網絡請求的方法都是完全同步的。

ts
interface S3File extends Blob {
  slice(start: number, end?: number): S3File;
  exists(): Promise<boolean>;
  unlink(): Promise<void>;
  presign(options: S3Options): string;
  text(): Promise<string>;
  json(): Promise<any>;
  bytes(): Promise<Uint8Array>;
  arrayBuffer(): Promise<ArrayBuffer>;
  stream(options: S3Options): ReadableStream;
  write(
    data: string | Uint8Array | ArrayBuffer | Blob | ReadableStream | Response | Request,
    options?: BlobPropertyBag,
  ): Promise<number>;

  exists(options?: S3Options): Promise<boolean>;
  unlink(options?: S3Options): Promise<void>;
  delete(options?: S3Options): Promise<void>;
  presign(options?: S3Options): string;

  stat(options?: S3Options): Promise<S3Stat>;
  /**
   * 大小不同步可用,因為它需要網絡請求。
   *
   * @deprecated 使用 `stat()` 代替。
   */
  size: NaN;

  // ... 為簡潔起見省略更多
}

Bun.file() 一樣,S3File 擴展了 Blob,因此 Blob 上可用的所有方法也可用於 S3File。從本地文件讀取數據的 API 也適用於從 S3 讀取數據。

方法輸出
await s3File.text()string
await s3File.bytes()Uint8Array
await s3File.json()JSON
await s3File.stream()ReadableStream
await s3File.arrayBuffer()ArrayBuffer

這意味著將 S3File 實例與 fetch()Response 和其他接受 Blob 實例的 Web API 一起使用可以直接工作。

使用 slice 部分讀取

要讀取文件的部分范圍,你可以使用 slice 方法。

ts
const partial = s3file.slice(0, 1024);

// 將部分范圍讀取為 Uint8Array
const bytes = await partial.bytes();

// 將部分范圍讀取為字符串
const text = await partial.text();

在內部,這通過使用 HTTP Range 頭僅請求你想要的字節。這個 slice 方法與 Blob.prototype.slice 相同。

從 S3 刪除文件

要從 S3 刪除文件,你可以使用 delete 方法。

ts
await s3file.delete();
// await s3File.unlink();

deleteunlink 相同。

錯誤碼

當 Bun 的 S3 API 拋出錯誤時,它將具有與以下值之一匹配的 code 屬性:

  • ERR_S3_MISSING_CREDENTIALS
  • ERR_S3_INVALID_METHOD
  • ERR_S3_INVALID_PATH
  • ERR_S3_INVALID_ENDPOINT
  • ERR_S3_INVALID_SIGNATURE
  • ERR_S3_INVALID_SESSION_TOKEN

當 S3 對象存儲服務返回錯誤(即不是 Bun)時,它將是 S3Error 實例(名稱為 "S3Error"Error 實例)。

S3Client 靜態方法

S3Client 類提供幾種用於與 S3 交互的靜態方法。

S3Client.write(靜態)

要將數據直接寫入存儲桶中的路徑,你可以使用 S3Client.write 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

// 寫入字符串
await S3Client.write("my-file.txt", "Hello World");

// 使用類型寫入 JSON
await S3Client.write("data.json", JSON.stringify({ hello: "world" }), {
  ...credentials,
  type: "application/json",
});

// 從 fetch 寫入
const res = await fetch("https://example.com/data");
await S3Client.write("data.bin", res, credentials);

// 使用 ACL 寫入
await S3Client.write("public.html", html, {
  ...credentials,
  acl: "public-read",
  type: "text/html",
});

這等同於調用 new S3Client(credentials).write("my-file.txt", "Hello World")

S3Client.presign(靜態)

要為 S3 文件生成預簽名 URL,你可以使用 S3Client.presign 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

const url = S3Client.presign("my-file.txt", {
  ...credentials,
  expiresIn: 3600,
});

這等同於調用 new S3Client(credentials).presign("my-file.txt", { expiresIn: 3600 })

S3Client.list(靜態)

要列出存儲桶中的一些或全部(最多 1,000 個)對象,你可以使用 S3Client.list 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

// 列出存儲桶中的(最多)1000 個對象
const allObjects = await S3Client.list(null, credentials);

// 列出 `uploads/` 前綴下的(最多)500 個對象,每個對象帶有所有者字段
const uploads = await S3Client.list({
  prefix: 'uploads/',
  maxKeys: 500,
  fetchOwner: true,
}, credentials);

// 檢查是否有更多結果可用
if (uploads.isTruncated) {
  // 列出 `uploads/` 前綴下的下一批對象
  const moreUploads = await S3Client.list({
    prefix: 'uploads/',
    maxKeys: 500,
    startAfter: uploads.contents!.at(-1).key
    fetchOwner: true,
  }, credentials);
}

這等同於調用 new S3Client(credentials).list()

S3Client.exists(靜態)

要檢查 S3 文件是否存在,你可以使用 S3Client.exists 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

const exists = await S3Client.exists("my-file.txt", credentials);

相同的方法也適用於 S3File 實例。

ts
import { s3 } from "bun";

const s3file = s3.file("my-file.txt", {
  // ...credentials,
});

const exists = await s3file.exists();

S3Client.size(靜態)

要快速檢查 S3 文件的大小而無需下載它,你可以使用 S3Client.size 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

const bytes = await S3Client.size("my-file.txt", credentials);

這等同於調用 new S3Client(credentials).size("my-file.txt")

S3Client.stat(靜態)

要獲取 S3 文件的大小、etag 和其他元數據,你可以使用 S3Client.stat 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
  // endpoint: "https://<account-id>.r2.cloudflarestorage.com", // Cloudflare R2
};

const stat = await S3Client.stat("my-file.txt", credentials);
txt
{
  etag: "\"7a30b741503c0b461cc14157e2df4ad8\"",
  lastModified: 2025-01-07T00:19:10.000Z,
  size: 1024,
  type: "text/plain;charset=utf-8",
}

S3Client.delete(靜態)

要刪除 S3 文件,你可以使用 S3Client.delete 靜態方法。

ts
import { S3Client } from "bun";

const credentials = {
  accessKeyId: "your-access-key",
  secretAccessKey: "your-secret-key",
  bucket: "my-bucket",
  // endpoint: "https://s3.us-east-1.amazonaws.com",
};

await S3Client.delete("my-file.txt", credentials);
// 等同於
// await new S3Client(credentials).delete("my-file.txt");

// S3Client.unlink 是 S3Client.delete 的別名
await S3Client.unlink("my-file.txt", credentials);

s3:// 協議

為了更容易對本地文件和 S3 文件使用相同的代碼,fetchBun.file() 中支持 s3:// 協議。

ts
const response = await fetch("s3://my-bucket/my-file.txt");
const file = Bun.file("s3://my-bucket/my-file.txt");

你還可以將 s3 選項傳遞給 fetchBun.file 函數。

ts
const response = await fetch("s3://my-bucket/my-file.txt", {
  s3: {
    accessKeyId: "your-access-key",
    secretAccessKey: "your-secret-key",
    endpoint: "https://s3.us-east-1.amazonaws.com",
  },
  headers: {
    range: "bytes=0-1023",
  },
});

UTF-8、UTF-16 和 BOM(字節順序標記)

ResponseBlob 一樣,S3File 默認假設 UTF-8 編碼。

當在 S3File 上調用 text()json() 方法之一時:

  • 當檢測到 UTF-16 字節順序標記 (BOM) 時,它將被視為 UTF-16。JavaScriptCore 原生支持 UTF-16,因此它跳過 UTF-8 轉碼過程(並剝離 BOM)。這主要是好的,但它確實意味著如果你的 UTF-16 字符串中有無效的代理對字符,它們將傳遞給 JavaScriptCore(與源代碼相同)。
  • 當檢測到 UTF-8 BOM 時,它在字符串傳遞給 JavaScriptCore 之前被剝離,無效的 UTF-8 碼點被替換為 Unicode 替換字符 (\uFFFD)。
  • 不支持 UTF-32。

Bun學習網由www.bunjs.com.cn整理維護