Skip to main content
Bun 实现了 WHATWG 的 fetch 标准,同时进行了扩展以满足服务端 JavaScript 的需求。 Bun 也实现了 node:http,但通常推荐使用 fetch

发送 HTTP 请求

要发送 HTTP 请求,请使用 fetch
fetch 也支持 HTTPS URL。
你也可以传递一个 Request 对象给 fetch

发送 POST 请求

要发送 POST 请求,传入一个 method 属性值为 "POST" 的对象。
body 可以是字符串、FormData 对象、ArrayBufferBlobMDN 文档中列出的其他请求体类型。

代理请求

要代理请求,传入一个对象,并将 proxy 属性设置为 URL 字符串、URL 实例,或将其设置为一个 url 为字符串或 URL 的对象:
要向代理服务器发送自定义请求头,请传入一个对象:
这些 headers 会直接在 CONNECT 请求(针对 HTTPS 目标)或代理请求(针对 HTTP 目标)中发送给代理。如果你提供了 Proxy-Authorization 头,它会覆盖代理 URL 中的任何凭据。

自定义请求头

要设置自定义请求头,传入一个带有 headers 属性的对象。
你也可以使用 Headers 对象设置请求头。

响应体

要读取响应体,使用以下方法之一:
  • response.text(): Promise<string>:返回包含响应体文本的 Promise。
  • response.json(): Promise<any>:返回包含响应体 JSON 对象的 Promise。
  • response.formData(): Promise<FormData>:返回包含响应体 FormData 对象的 Promise。
  • response.bytes(): Promise<Uint8Array>:返回包含响应体 Uint8Array 的 Promise。
  • response.arrayBuffer(): Promise<ArrayBuffer>:返回包含响应体 ArrayBuffer 的 Promise。
  • response.blob(): Promise<Blob>:返回包含响应体 Blob 的 Promise。

流式响应体

你可以使用异步迭代器来流式读取响应体。
你也可以直接访问 ReadableStream

流式请求体

你也可以使用 ReadableStream 来流式传输请求体数据:
使用 HTTP(S) 协议时的流式传输要点:
  • 数据会直接流式传输到网络,而不会将整个请求体缓存在内存中
  • 如果连接断开,流会被取消
  • 除非流的大小已知,否则不会自动设置 Content-Length
使用 S3 时:
  • 对于 PUT/POST 请求,Bun 会自动使用分块上传
  • 流以块的形式消费,并行上传
  • 可以通过 S3 选项监控上传进度

带超时的 URL 请求

要带超时发送请求,使用 AbortSignal.timeout

取消请求

要取消请求,使用 AbortController

Unix 域套接字

要通过 Unix 域套接字请求 URL,使用 unix: string 选项:

TLS

使用客户端证书时,使用 tls 选项:

自定义 TLS 验证

要自定义 TLS 验证,请在 tls 中使用 checkServerIdentity 选项:
此选项类似于 Node 的 tls 模块中的同名选项。

禁用 TLS 验证

要禁用 TLS 验证,将 rejectUnauthorized 设为 false
这可以避免使用自签名证书时出现 SSL 错误,但会禁用 TLS 验证,因此请谨慎使用。

请求选项

除了标准的 fetch 选项,Bun 还提供了几个扩展:

协议支持

除了 HTTP(S) 之外,Bun 的 fetch 还支持多种其他协议:

S3 URL - s3://

Bun 支持直接从 S3 桶读取。
使用 S3 时,只有 PUT 和 POST 方法支持请求体。对于上传,Bun 会自动对流式请求体使用分块上传。 请参阅 S3 文档。

本地文件 URL - file://

你可以用 file: 协议获取本地文件:
在 Windows 上,路径会自动规范化:

Data URL - data:

Bun 支持 data: URL 方案:

Blob URL - blob:

你可以使用 URL.createObjectURL() 创建的 URL 来获取 Blob:

错误处理

Bun 的 fetch 实现包含多个特定错误场景:
  • 对 GET/HEAD 方法使用请求体会抛出错误(这是 fetch API 的预期行为)
  • 同时使用 proxyunix 选项会抛出错误
  • rejectUnauthorizedtrue(或未定义)时,TLS 证书验证失败
  • S3 操作可能会抛出与身份验证或权限相关的特定错误

Content-Type 处理

当未明确提供时,Bun 会自动为请求体设置 Content-Type 头:
  • 对于 Blob 对象,使用 Blob 的 type
  • 对于 FormData,设置合适的 multipart 边界

调试

要进行调试,请将 verbose: true 传递给 fetch
这会将请求和响应标头打印到终端:
verbose: boolean 是 Bun 特有的扩展,不属于 Web 标准的 fetch API。

性能

在发送 HTTP 请求之前,Bun 必须解析 DNS、连接 TCP 套接字,有时还要完成 TLS 握手。每个步骤都需要时间,尤其是在 DNS 服务器速度较慢或网络连接质量较差时。请求完成后,读取响应体同样需要时间和内存。 Bun 提供了用于优化这些步骤的 API。

DNS 预读取

当你知道即将连接某个主机,并希望避免初始 DNS 查询时,可以使用 dns.prefetch

DNS 缓存

默认情况下,Bun 会在内存中缓存并去重 DNS 查询,最长缓存 30 秒。dns.getCacheStats() 会返回缓存统计信息。 参见 DNS 缓存

预连接到主机

fetch.preconnect 会在你准备向某个主机发送请求之前,启动 DNS 查询、TCP 套接字连接和 TLS 握手。
fetch.preconnect 后立即调用 fetch 并不会让请求更快。只有在确定主机和发送请求之间存在时间间隔时,预连接才能发挥作用。

启动时预连接

要在启动时预连接到某个主机,请传入 --fetch-preconnect
--fetch-preconnect 类似于 HTML 中的 <link rel="preconnect">。Windows 尚未实现此功能;如果你需要在 Windows 上使用,请提交 issue。

连接池与 HTTP 长连接

Bun 会自动复用连接到同一主机的连接。这称为连接池,可以显著减少建立连接所需的时间。

同时连接数限制

默认情况下,Bun 将同时进行的 fetch 请求数限制为 256,原因有二:
  • 改善系统整体稳定性。操作系统对同时打开的 TCP 套接字数有上限,通常在几千左右。接近该限制时,会导致整台电脑异常,应用挂起或崩溃。
  • 鼓励 HTTP Keep-Alive 的连接复用。对于短时 HTTP 请求,最慢的步骤往往是初次连接。连接复用可节省大量时间。
超过限制后,请求会进入队列,并在下一个请求结束后立即发送。 要提高该限制,请设置 BUN_CONFIG_MAX_HTTP_REQUESTS 环境变量:
该限制的最大值为 65,535。最大端口号也是 65,535,因此单台计算机很难超过这一限制。

响应体缓冲

读取响应体最快的方式是使用以下方法之一:
  • 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 将响应体写入磁盘文件:

实现细节

  • 默认启用连接池,但可以通过 keepalive: false"Connection: close" 请求头针对单个请求禁用。
  • 在特定条件下,大文件上传会使用操作系统的 sendfile 系统调用进行优化:
    • 文件必须大于 32KB
    • 请求不能使用代理
    • 在 macOS 上,只有普通文件(不包括管道、套接字或设备)可以使用 sendfile
    • 不满足这些条件,或使用 S3/流式上传时,Bun 会改为将文件读入内存
    • 对于 HTTP(而非 HTTPS)请求,这项优化尤其有效,因为文件可以直接从内核发送到网络协议栈
  • S3 操作会自动处理请求签名并合并身份验证请求头
其中许多功能是 Bun 针对标准 fetch API 提供的专属扩展。