fetch 标准,并添加了一些扩展以满足服务端 JavaScript 的需求。
Bun 也实现了 node:http,但通常推荐使用 fetch。
发送 HTTP 请求
要发送 HTTP 请求,使用fetch:
fetch 也支持 HTTPS URL。
fetch 传递一个 Request 对象。
发送 POST 请求
要发送 POST 请求,传递一个method 属性为 "POST" 的对象。
body 可以是字符串、FormData 对象、ArrayBuffer、Blob,或其他列在 MDN 文档中的主体类型。
代理请求
要代理请求,传递一个proxy 属性为 URL 字符串、URL 实例,或一个包含 url 属性的对象:
headers 会直接发送给代理——在 CONNECT 请求(针对 HTTPS 目标)或代理请求(针对 HTTP 目标)中。如果你提供了 Proxy-Authorization 头部,它会覆盖代理 URL 中的任何凭据。
自定义头部
要设置自定义头部,传递一个headers 属性为对象的参数。
响应体
要读取响应体,使用以下方法之一:response.text(): Promise<string>:返回一个 Promise,解析为字符串格式的响应体。response.json(): Promise<any>:返回一个 Promise,解析为 JSON 对象的响应体。response.formData(): Promise<FormData>:返回一个 Promise,解析为FormData对象的响应体。response.bytes(): Promise<Uint8Array>:返回一个 Promise,解析为Uint8Array的响应体。response.arrayBuffer(): Promise<ArrayBuffer>:返回一个 Promise,解析为ArrayBuffer的响应体。response.blob(): Promise<Blob>:返回一个 Promise,解析为Blob的响应体。
流式传输响应体
你可以使用异步迭代器来流式传输响应体。ReadableStream。
流式传输请求体
你也可以使用ReadableStream 在请求体中流式传输数据:
- 数据直接流式传输到网络,无需将整个请求体缓冲到内存中
- 如果连接断开,流会被取消
- 除非流具有已知大小,否则不会自动设置
Content-Length头部
- 对于 PUT/POST 请求,Bun 自动使用分片上传
- 流会分块消费并并行上传
- 可以通过 S3 选项监控进度
带超时的 URL 请求
要带超时请求 URL,使用AbortSignal.timeout:
取消请求
要取消请求,使用AbortController:
Unix 域套接字
要使用 Unix 域套接字请求 URL,使用unix: string 选项:
TLS
要使用客户端证书,使用tls 选项:
自定义 TLS 验证
要自定义 TLS 验证,使用tls 中的 checkServerIdentity 选项:
tls 模块中的类似选项。
禁用 TLS 验证
要禁用 TLS 验证,将rejectUnauthorized 设置为 false:
请求选项
除了标准的 fetch 选项之外,Bun 还提供了几个扩展:协议支持
除了 HTTP(S),Bun 的 fetch 还支持多种其他协议:S3 URL - s3://
Bun 支持直接从 S3 存储桶获取数据。
文件 URL - file://
你可以使用 file: 协议获取本地文件:
Data URL - data:
Bun 支持 data: URL 方案:
Blob URL - blob:
你可以使用 URL.createObjectURL() 创建的 URL 来获取 blob:
错误处理
Bun 的 fetch 实现包含几个特定的错误情况:- 使用 GET/HEAD 方法时使用请求体会抛出错误(这是 fetch API 的预期行为)
- 同时使用
proxy和unix选项会抛出错误 - 当
rejectUnauthorized为 true(或未定义)时,TLS 证书验证失败 - S3 操作可能会抛出与认证或权限相关的特定错误
Content-Type 处理
当未显式提供时,Bun 会自动为请求体设置Content-Type 头部:
- 对于
Blob对象,使用 blob 的type - 对于
FormData,设置适当的 multipart 边界
调试
用于调试,向fetch 传递 verbose: true:
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 keep-alive
Bun 会自动复用到同一主机的连接。这称为连接池,可以显著减少建立连接所需的时间。并发连接限制
默认情况下,Bun 将并发fetch 请求数量限制为 256,原因有二:
- 它提高了整体系统稳定性。操作系统对并发打开的 TCP 套接字数量有上限,通常在数千以内。接近此限制会导致整台计算机行为异常。应用程序挂起和崩溃。
- 它鼓励 HTTP Keep-Alive 连接复用。对于短生命周期的 HTTP 请求,最慢的步骤通常是初始连接建立。复用连接可以节省大量时间。
BUN_CONFIG_MAX_HTTP_REQUESTS 环境变量:
响应缓冲
读取响应体最快的方法是使用以下方法之一: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 操作自动处理签名请求和合并认证头部