Bun implements the WHATWG fetch standard, with some extensions to meet the needs of server-side JavaScript.
Bun also implements node:http, but fetch is generally recommended instead.
发送 HTTP 请求
To send an HTTP request, use fetch
const response = await fetch("http://example.com");
console.log(response.status); // => 200
const text = await response.text(); // or response.json(), response.formData(), etc.
fetch also works with HTTPS URLs.
const response = await fetch("https://example.com");
You can also pass fetch a Request object.
const request = new Request("http://example.com", {
method: "POST",
body: "Hello, world!",
});
const response = await fetch(request);
发送 POST 请求
To send a POST request, pass an object with the method property set to "POST".
const response = await fetch("http://example.com", {
method: "POST",
body: "Hello, world!",
});
body can be a string, a FormData object, an ArrayBuffer, a Blob, and more. See the MDN documentation for more information.
代理请求
To proxy a request, pass an object with the proxy property set to a URL.
const response = await fetch("http://example.com", {
proxy: "http://proxy.com",
});
自定义标头
To set custom headers, pass an object with the headers property set to an object.
const response = await fetch("http://example.com", {
headers: {
"X-Custom-Header": "value",
},
});
You can also set headers using the Headers object.
const headers = new Headers();
headers.append("X-Custom-Header", "value");
const response = await fetch("http://example.com", {
headers,
});
响应正文
To read the response body, use one of the following methods
response.text(): Promise<string>: Returns a promise that resolves with the response body as a string.response.json(): Promise<any>: Returns a promise that resolves with the response body as a JSON object.response.formData(): Promise<FormData>: Returns a promise that resolves with the response body as aFormDataobject.response.bytes(): Promise<Uint8Array>: Returns a promise that resolves with the response body as aUint8Array.response.arrayBuffer(): Promise<ArrayBuffer>: Returns a promise that resolves with the response body as anArrayBuffer.response.blob(): Promise<Blob>: Returns a promise that resolves with the response body as aBlob.
流式传输响应正文
You can use async iterators to stream the response body.
const response = await fetch("http://example.com");
for await (const chunk of response.body) {
console.log(chunk);
}
You can also more directly access the ReadableStream object.
const response = await fetch("http://example.com");
const stream = response.body;
const reader = stream.getReader();
const { value, done } = await reader.read();
流式传输请求正文
You can also stream data in request bodies using a ReadableStream
const stream = new ReadableStream({
start(controller) {
controller.enqueue("Hello");
controller.enqueue(" ");
controller.enqueue("World");
controller.close();
},
});
const response = await fetch("http://example.com", {
method: "POST",
body: stream,
});
When using streams with HTTP(S)
- The data is streamed directly to the network without buffering the entire body in memory
- If the connection is lost, the stream will be canceled
- The
Content-Lengthheader is not automatically set unless the stream has a known size
When using streams with S3
- For PUT/POST requests, Bun automatically uses multipart upload
- The stream is consumed in chunks and uploaded in parallel
- Progress can be monitored through the S3 options
带超时的 URL 获取
To fetch a URL with a timeout, use AbortSignal.timeout
const response = await fetch("http://example.com", {
signal: AbortSignal.timeout(1000),
});
取消请求
To cancel a request, use an AbortController
const controller = new AbortController();
const response = await fetch("http://example.com", {
signal: controller.signal,
});
controller.abort();
Unix 域套接字
To fetch a URL using a Unix domain socket, use the unix: string option
const response = await fetch("https://hostname/a/path", {
unix: "/var/run/path/to/unix.sock",
method: "POST",
body: JSON.stringify({ message: "Hello from Bun!" }),
headers: {
"Content-Type": "application/json",
},
});
TLS
To use a client certificate, use the tls option
await fetch("https://example.com", {
tls: {
key: Bun.file("/path/to/key.pem"),
cert: Bun.file("/path/to/cert.pem"),
// ca: [Bun.file("/path/to/ca.pem")],
},
});
自定义 TLS 验证
To customize the TLS validation, use the checkServerIdentity option in tls
await fetch("https://example.com", {
tls: {
checkServerIdentity: (hostname, peerCertificate) => {
// Return an Error if the certificate is invalid
},
},
});
This is similar to how it works in Node's net module.
禁用 TLS 验证
To disable TLS validation, set rejectUnauthorized to false
await fetch("https://example.com", {
tls: {
rejectUnauthorized: false,
},
});
This is especially useful to avoid SSL errors when using self-signed certificates, but this disables TLS validation and should be used with caution.
请求选项
In addition to the standard fetch options, Bun provides several extensions
const response = await fetch("http://example.com", {
// Control automatic response decompression (default: true)
// Supports gzip, deflate, brotli (br), and zstd
decompress: true,
// Disable connection reuse for this request
keepalive: false,
// Debug logging level
verbose: true, // or "curl" for more detailed output
});
协议支持
Beyond HTTP(S), Bun's fetch supports several additional protocols
S3 URLs - s3://
Bun supports fetching from S3 buckets directly.
// Using environment variables for credentials
const response = await fetch("s3://my-bucket/path/to/object");
// Or passing credentials explicitly
const response = await fetch("s3://my-bucket/path/to/object", {
s3: {
accessKeyId: "YOUR_ACCESS_KEY",
secretAccessKey: "YOUR_SECRET_KEY",
region: "us-east-1",
},
});
Note: Only PUT and POST methods support request bodies when using S3. For uploads, Bun automatically uses multipart upload for streaming bodies.
You can read more about Bun's S3 support in the S3 documentation.
File URLs - file://
You can fetch local files using the file: protocol
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();
On Windows, paths are automatically normalized
// Both work on Windows
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");
Data URLs - data:
Bun supports the data: URL scheme
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await response.text(); // "Hello, World!"
Blob URLs - blob:
You can fetch blobs using URLs created by URL.createObjectURL()
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const response = await fetch(url);
错误处理
Bun's fetch implementation includes several specific error cases
- Using a request body with GET/HEAD methods will throw an error (which is expected for the fetch API)
- Attempting to use both
proxyandunixoptions together will throw an error - TLS certificate validation failures when
rejectUnauthorizedis true (or undefined) - S3 operations may throw specific errors related to authentication or permissions
Content-Type 处理
Bun automatically sets the Content-Type header for request bodies when not explicitly provided
- For
Blobobjects, uses the blob'stype - For
FormData, sets appropriate multipart boundary
调试
To help with debugging, you can pass verbose: true to fetch
const response = await fetch("http://example.com", {
verbose: true,
});
This will print the request and response headers to your terminal
[fetch] > HTTP/1.1 GET http://example.com/
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.0
[fetch] > Accept: */*
[fetch] > Host: example.com
[fetch] > Accept-Encoding: gzip, deflate, br, zstd
[fetch] < 200 OK
[fetch] < Content-Encoding: gzip
[fetch] < Age: 201555
[fetch] < Cache-Control: max-age=604800
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Date: Sun, 21 Jul 2024 02:41:14 GMT
[fetch] < Etag: "3147526947+gzip"
[fetch] < Expires: Sun, 28 Jul 2024 02:41:14 GMT
[fetch] < Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
[fetch] < Server: ECAcc (sac/254F)
[fetch] < Vary: Accept-Encoding
[fetch] < X-Cache: HIT
[fetch] < Content-Length: 648
Note: verbose: boolean is not part of the Web standard fetch API and is specific to Bun.
性能
在发送 HTTP 请求之前,必须执行 DNS 查找。这可能需要很长时间,尤其是在 DNS 服务器缓慢或网络连接不佳的情况下。
DNS 查找完成后,必须连接 TCP 套接字,并且可能需要执行 TLS 握手。这也可能需要很长时间。
请求完成后,消耗响应正文也可能需要大量的时间和内存。
在每一步,Bun 都提供 API 来帮助您优化应用程序的性能。
DNS 预取
要预取 DNS 条目,可以使用 dns.prefetch API。当您知道很快需要连接到某个主机并希望避免初始 DNS 查找时,此 API 非常有用。
import { dns } from "bun";
dns.prefetch("bun.com");
DNS 缓存
默认情况下,Bun 会在内存中缓存并去重 DNS 查询,最多缓存 30 秒。您可以通过调用 dns.getCacheStats() 来查看缓存统计信息。
要了解有关 Bun 中 DNS 缓存的更多信息,请参阅 DNS 缓存 文档。
预连接到主机
要预连接到主机,可以使用 fetch.preconnect API。当您知道很快需要连接到某个主机并希望提前启动初始 DNS 查找、TCP 套接字连接和 TLS 握手时,此 API 非常有用。
import { fetch } from "bun";
fetch.preconnect("https://bun.net.cn");
注意:在调用 fetch.preconnect 后立即调用 fetch 不会使您的请求更快。预连接仅在您知道很快需要连接到某个主机但尚未准备好发起请求时才有效。
启动时预连接
要启动时预连接到主机,可以传递 --fetch-preconnect。
bun --fetch-preconnect https://bun.net.cn ./my-script.ts这类似于 HTML 中的 <link rel="preconnect">。
此功能尚未在 Windows 上实现。如果您有兴趣在 Windows 上使用此功能,请提交一个 issue,我们可以在 Windows 上实现支持。
连接池和 HTTP Keep-Alive
Bun 会自动重用与同一主机的连接。这被称为连接池。这可以显著减少建立连接所需的时间。您无需执行任何操作即可启用此功能;它是自动的。
并发连接限制
默认情况下,Bun 将并发 fetch 请求的最大数量限制为 256。我们这样做的原因有很多:
- 这提高了整体系统稳定性。操作系统对并发打开的 TCP 套接字数量有一个上限,通常是几千。接近此限制会导致您的整个计算机行为异常。应用程序挂起和崩溃。
- 它鼓励 HTTP Keep-Alive 连接重用。对于短暂的 HTTP 请求,最慢的步骤通常是初始连接设置。重用连接可以节省大量时间。
当超出限制时,请求将被排队,并在下一个请求结束时立即发送。
您可以通过 BUN_CONFIG_MAX_HTTP_REQUESTS 环境变量来增加并发连接的最大数量。
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts此限制的最大值为 65,536。最大端口号为 65,535,因此任何一台计算机都很难超过此限制。
响应缓冲
Bun 竭尽全力优化读取响应正文的性能。读取响应正文的最快方法是使用以下方法之一:
response.text(): Promise<string>response.json(): Promise<any>response.formData(): Promise<FormData>response.bytes(): Promise<Uint8Array>response.arrayBuffer(): Promise<ArrayBuffer>response.blob(): Promise<Blob>
您还可以使用 Bun.write 将响应正文写入磁盘文件。
import { write } from "bun";
await write("output.txt", response);
实现细节
- 连接池默认启用,但可以通过
keepalive: false为每个请求禁用。"Connection: close"头也可以用来禁用 keep-alive。 - 在特定条件下,使用操作系统的
sendfile系统调用来优化大文件上传。- 文件必须大于 32KB。
- 请求不得使用代理。
- 在 macOS 上,只有常规文件(而非管道、套接字或设备)可以使用
sendfile。 - 当不满足这些条件时,或者在使用 S3/流式上传时,Bun 会回退到将文件读入内存。
- 此优化对于 HTTP(非 HTTPS)请求尤其有效,其中文件可以直接从内核发送到网络堆栈。
- S3 操作会自动处理签名请求和合并身份验证头。
注意:其中许多功能都是 Bun 对标准 fetch API 的特定扩展。