fetch 标准,同时进行了扩展以满足服务端 JavaScript 的需求。
Bun 也实现了 node:http,但通常推荐使用 fetch。
发送 HTTP 请求
要发送 HTTP 请求,使用fetch
fetch 也支持 HTTPS URL。
Request 对象给 fetch。
发送 POST 请求
要发送 POST 请求,传入一个method 属性值为 "POST" 的对象。
body 可以是字符串、FormData 对象、ArrayBuffer、Blob 等更多类型。更多信息请参考 MDN 文档。
代理请求
要代理请求,传入一个带有proxy 属性的 URL 字符串:
headers 会直接在 CONNECT 请求(针对 HTTPS 目标)或代理请求(针对 HTTP 目标)中发送给代理。如果你提供了 Proxy-Authorization 头,它会覆盖代理 URL 中的任何凭据。
自定义请求头
要设置自定义请求头,传入一个带有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 来流式传输请求体数据:
- 数据直接流式传输到网络,而不需要将整个请求体缓存在内存中
- 如果连接丢失,流会被取消
- 除非流大小已知,否则不会自动设置
Content-Length头
- 对于 PUT/POST 请求,Bun 会自动使用分块上传
- 流以块的形式消费,并行上传
- 可以通过 S3 选项监控上传进度
带超时的 URL 请求
要带超时发送请求,使用AbortSignal.timeout:
取消请求
要取消请求,使用AbortController:
Unix 域套接字
要通过 Unix 域套接字请求 URL,使用unix: string 选项:
TLS
使用客户端证书时,使用tls 选项:
自定义 TLS 验证
要定制 TLS 验证,使用tls 的 checkServerIdentity 选项:
net 模块的工作方式类似。
禁用 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 不是 Web 标准 fetch API 的一部分,仅针对 Bun 特有。
性能
HTTP 请求发送前,必须完成 DNS 查找。这一步可能耗时较长,尤其当 DNS 服务器缓慢或网络差时。 DNS 查找后,必须连接 TCP 套接字,且可能进行 TLS 握手。这也可能耗费显著时间。 请求完成后,读取响应体也可能花费大量时间和内存。 在各个阶段,Bun 提供了 API 以帮助你优化应用性能。DNS 预读取
要预读取 DNS 条目,可以使用dns.prefetch API。当你知道将要连接某个主机且想避免初始 DNS 查找时,此 API 非常有用。
DNS 缓存
默认情况下,Bun 会将 DNS 查询的结果缓存并去重,缓存时长最多 30 秒。你可以通过调用dns.getCacheStats() 查看缓存状态。
想了解更多关于 Bun 中的 DNS 缓存,请参阅 DNS 缓存 文档。
预连接到主机
要预连接到主机,可以使用fetch.preconnect API。当你知道将很快要连接某个主机并希望提前开始 DNS 查找、TCP 建连和 TLS 握手时,此 API 非常有用。
fetch.preconnect 马上发起 fetch 请求不会更快。预连接仅在你知道将很快连接某主机,但尚未准备好发起请求时生效。
启动时预连接
要在启动时预连接某主机,可以传入--fetch-preconnect 参数:
<link rel="preconnect">。
该功能尚未在 Windows 上实现。如果你希望在 Windows 上使用该功能,请提交 issue,方便我们实现支持。
连接池与 HTTP 长连接
Bun 会自动重用对同一个主机的连接,即连接池。这能显著减少建立连接所需的时间。你无需做任何配置,默认启用。同时连接数限制
默认情况下,Bun 限制最大同时进行的fetch 请求数量为 256。这样做有几个原因:
- 改善系统整体稳定性。操作系统对同时打开的 TCP 套接字数有上限,通常在几千左右。接近该限制时,会导致整台电脑异常,应用挂起或崩溃。
- 鼓励 HTTP Keep-Alive 的连接复用。对于短时 HTTP 请求,最慢的步骤往往是初次连接。连接复用可节省大量时间。
BUN_CONFIG_MAX_HTTP_REQUESTS 增加最大同时连接数:
响应体缓冲
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 将响应体写入磁盘文件:
实现细节
- 连接池默认启用,但每个请求可通过
keepalive: false禁用。同样,设置"Connection: close"头也会禁用长连接。 - 大文件上传会在特定条件下利用操作系统的
sendfile系统调用优化:- 文件必须大于 32KB
- 请求不能使用代理
- 在 macOS 上,仅常规文件(非管道、套接字或设备)支持
sendfile - 若条件不满足,或使用了 S3/流式上传,则回退到内存读取文件
- 此优化对 HTTP(非 HTTPS)请求特别有效,可直接将文件从内核发往网络栈
- S3 操作自动处理请求签名和合并认证头