Skip to content

O Bun implementa o padrão fetch do WHATWG, com algumas extensões para atender às necessidades do JavaScript do lado do servidor.

O Bun também implementa node:http, mas fetch é geralmente recomendado.

Enviando uma requisição HTTP

Para enviar uma requisição HTTP, use fetch

ts
const response = await fetch("http://example.com");

console.log(response.status); // => 200

const text = await response.text(); // ou response.json(), response.formData(), etc.

fetch também funciona com URLs HTTPS.

ts
const response = await fetch("https://example.com");

Você também pode passar para fetch um objeto Request.

ts
const request = new Request("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

const response = await fetch(request);

Enviando uma requisição POST

Para enviar uma requisição POST, passe um objeto com a propriedade method definida como "POST".

ts
const response = await fetch("http://example.com", {
  method: "POST",
  body: "Hello, world!",
});

body pode ser uma string, um objeto FormData, um ArrayBuffer, um Blob, e mais. Veja a documentação MDN para mais informações.

Proxying de requisições

Para fazer proxy de uma requisição, passe um objeto com a propriedade proxy definida como uma string URL:

ts
const response = await fetch("http://example.com", {
  proxy: "http://proxy.com",
});

Você também pode usar um formato de objeto para enviar headers customizados para o servidor proxy:

ts
const response = await fetch("http://example.com", {
  proxy: {
    url: "http://proxy.com",
    headers: {
      "Proxy-Authorization": "Bearer my-token",
      "X-Custom-Proxy-Header": "value",
    },
  },
});

Os headers são enviados diretamente ao proxy em requisições CONNECT (para alvos HTTPS) ou na requisição proxy (para alvos HTTP). Se você fornecer um header Proxy-Authorization, ele sobrescreve quaisquer credenciais na URL do proxy.

Headers customizados

Para definir headers customizados, passe um objeto com a propriedade headers definida como um objeto.

ts
const response = await fetch("http://example.com", {
  headers: {
    "X-Custom-Header": "value",
  },
});

Você também pode definir headers usando o objeto Headers.

ts
const headers = new Headers();
headers.append("X-Custom-Header", "value");

const response = await fetch("http://example.com", {
  headers,
});

Bodies de resposta

Para ler o body da resposta, use um dos seguintes métodos:

  • response.text(): Promise<string>: Retorna uma promise que resolve com o body da resposta como uma string.
  • response.json(): Promise<any>: Retorna uma promise que resolve com o body da resposta como um objeto JSON.
  • response.formData(): Promise<FormData>: Retorna uma promise que resolve com o body da resposta como um objeto FormData.
  • response.bytes(): Promise<Uint8Array>: Retorna uma promise que resolve com o body da resposta como um Uint8Array.
  • response.arrayBuffer(): Promise<ArrayBuffer>: Retorna uma promise que resolve com o body da resposta como um ArrayBuffer.
  • response.blob(): Promise<Blob>: Retorna uma promise que resolve com o body da resposta como um Blob.

Streaming de bodies de resposta

Você pode usar iteradores assíncronos para fazer stream do body da resposta.

ts
const response = await fetch("http://example.com");

for await (const chunk of response.body) {
  console.log(chunk);
}

Você também pode acessar mais diretamente o objeto ReadableStream.

ts
const response = await fetch("http://example.com");

const stream = response.body;

const reader = stream.getReader();
const { value, done } = await reader.read();

Streaming de bodies de requisição

Você também pode fazer stream de dados em bodies de requisição usando um ReadableStream:

ts
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,
});

Ao usar streams com HTTP(S):

  • Os dados são streamados diretamente para a rede sem bufferizar o body inteiro na memória
  • Se a conexão for perdida, o stream será cancelado
  • O header Content-Length não é definido automaticamente a menos que o stream tenha um tamanho conhecido

Ao usar streams com S3:

  • Para requisições PUT/POST, o Bun automaticamente usa upload multipart
  • O stream é consumido em chunks e enviado em paralelo
  • O progresso pode ser monitorado através das opções S3

Buscando uma URL com timeout

Para buscar uma URL com timeout, use AbortSignal.timeout:

ts
const response = await fetch("http://example.com", {
  signal: AbortSignal.timeout(1000),
});

Cancelando uma requisição

Para cancelar uma requisição, use um AbortController:

ts
const controller = new AbortController();

const response = await fetch("http://example.com", {
  signal: controller.signal,
});

controller.abort();

Unix domain sockets

Para buscar uma URL usando um Unix domain socket, use a opção unix: string:

ts
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

Para usar um certificado de cliente, use a opção tls:

ts
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")],
  },
});

Validação TLS customizada

Para customizar a validação TLS, use a opção checkServerIdentity em tls

ts
await fetch("https://example.com", {
  tls: {
    checkServerIdentity: (hostname, peerCertificate) => {
      // Retorna um Error se o certificado for inválido
    },
  },
});

Isto é similar a como funciona no módulo net do Node.

Desabilitar validação TLS

Para desabilitar validação TLS, defina rejectUnauthorized como false:

ts
await fetch("https://example.com", {
  tls: {
    rejectUnauthorized: false,
  },
});

Isto é especialmente útil para evitar erros SSL ao usar certificados auto-assinados, mas desabilita a validação TLS e deve ser usado com cautela.

Opções de requisição

Além das opções fetch padrão, o Bun fornece várias extensões:

ts
const response = await fetch("http://example.com", {
  // Controla descompressão automática da resposta (padrão: true)
  // Suporta gzip, deflate, brotli (br), e zstd
  decompress: true,

  // Desabilita reuso de conexão para esta requisição
  keepalive: false,

  // Nível de log de debug
  verbose: true, // ou "curl" para saída mais detalhada
});

Suporte a protocolos

Além de HTTP(S), o fetch do Bun suporta vários protocolos adicionais:

URLs S3 - s3://

O Bun suporta fetch de buckets S3 diretamente.

ts
// Usando variáveis de ambiente para credenciais
const response = await fetch("s3://my-bucket/path/to/object");

// Ou passando credenciais explicitamente
const response = await fetch("s3://my-bucket/path/to/object", {
  s3: {
    accessKeyId: "YOUR_ACCESS_KEY",
    secretAccessKey: "YOUR_SECRET_KEY",
    region: "us-east-1",
  },
});

Nota: Apenas métodos PUT e POST suportam bodies de requisição ao usar S3. Para uploads, o Bun automaticamente usa upload multipart para streaming de bodies.

Você pode ler mais sobre o suporte S3 do Bun na documentação S3.

URLs de arquivo - file://

Você pode buscar arquivos locais usando o protocolo file::

ts
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();

No Windows, caminhos são automaticamente normalizados:

ts
// Ambos funcionam no Windows
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");

URLs Data - data:

O Bun suporta o esquema de URL data::

ts
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await response.text(); // "Hello, World!"

URLs Blob - blob:

Você pode buscar blobs usando URLs criadas por URL.createObjectURL():

ts
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const response = await fetch(url);

Tratamento de erros

A implementação fetch do Bun inclui vários casos de erro específicos:

  • Usar um body de requisição com métodos GET/HEAD lançará um erro (o que é esperado para a API fetch)
  • Tentar usar as opções proxy e unix juntas lançará um erro
  • Falhas de validação de certificado TLS quando rejectUnauthorized é true (ou undefined)
  • Operações S3 podem lançar erros específicos relacionados a autenticação ou permissões

Tratamento de Content-Type

O Bun automaticamente define o header Content-Type para bodies de requisição quando não fornecido explicitamente:

  • Para objetos Blob, usa o type do blob
  • Para FormData, define o boundary multipart apropriado

Debugging

Para ajudar com debugging, você pode passar verbose: true para fetch:

ts
const response = await fetch("http://example.com", {
  verbose: true,
});

Isto imprimirá os headers de requisição e resposta no seu terminal:

sh
[fetch] > HTTP/1.1 GET http://example.com/
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[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

Nota: verbose: boolean não faz parte da API fetch padrão Web e é específico do Bun.

Performance

Antes de uma requisição HTTP ser enviada, a busca DNS deve ser realizada. Isto pode levar uma quantidade significativa de tempo, especialmente se o servidor DNS for lento ou a conexão de rede for ruim.

Após a busca DNS, o socket TCP deve ser conectado e o handshake TLS pode precisar ser realizado. Isto também pode levar uma quantidade significativa de tempo.

Após a requisição completar, consumir o body da resposta também pode levar uma quantidade significativa de tempo e memória.

Em cada passo do caminho, o Bun fornece APIs para ajudar você a otimizar a performance da sua aplicação.

DNS prefetching

Para fazer prefetch de uma entrada DNS, você pode usar a API dns.prefetch. Esta API é útil quando você sabe que precisará conectar a um host em breve e quer evitar a busca DNS inicial.

ts
import { dns } from "bun";

dns.prefetch("bun.com");

Cache DNS

Por padrão, o Bun faz cache e deduplica consultas DNS em memória por até 30 segundos. Você pode ver as estatísticas do cache chamando dns.getCacheStats():

Para aprender mais sobre cache DNS no Bun, veja a documentação de cache DNS.

Pré-conexão a um host

Para pré-conectar a um host, você pode usar a API fetch.preconnect. Esta API é útil quando você sabe que precisará conectar a um host em breve e quer iniciar a busca DNS inicial, conexão de socket TCP, e handshake TLS cedo.

ts
import { fetch } from "bun";

fetch.preconnect("https://bun.com");

Nota: chamar fetch imediatamente após fetch.preconnect não tornará sua requisição mais rápida. Pré-conectar apenas ajuda se você sabe que precisará conectar a um host em breve, mas não está pronto para fazer a requisição ainda.

Pré-conexão na inicialização

Para pré-conectar a um host na inicialização, você pode passar --fetch-preconnect:

sh
bun --fetch-preconnect https://bun.com ./my-script.ts

Isto é meio que como <link rel="preconnect"> em HTML.

Este recurso ainda não está implementado no Windows. Se você estiver interessado em usar este recurso no Windows, por favor abra uma issue e podemos implementar suporte para ele no Windows.

Pool de conexões e HTTP keep-alive

O Bun automaticamente reutiliza conexões ao mesmo host. Isto é conhecido como pool de conexões. Isto pode reduzir significativamente o tempo que leva para estabelecer uma conexão. Você não precisa fazer nada para habilitar isto; é automático.

Limite de conexões simultâneas

Por padrão, o Bun limita o número máximo de requisições fetch simultâneas a 256. Fazemos isto por várias razões:

  • Melhora a estabilidade geral do sistema. Sistemas operacionais têm um limite superior no número de sockets TCP abertos simultâneos, geralmente nos baixos milhares. Aproximar-se deste limite faz com que todo o seu computador se comporte estranhamente. Aplicações travam e falham.
  • Incentiva o reuso de conexão HTTP Keep-Alive. Para requisições HTTP de curta duração, a etapa mais lenta é frequentemente a configuração inicial da conexão. Reutilizar conexões pode economizar muito tempo.

Quando o limite é excedido, as requisições são enfileiradas e enviadas assim que a próxima requisição termina.

Você pode aumentar o número máximo de conexões simultâneas via variável de ambiente BUN_CONFIG_MAX_HTTP_REQUESTS:

sh
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.ts

O valor máximo para este limite é atualmente 65.336. O número máximo de porta é 65.535, então é bastante difícil para qualquer computador exceder este limite.

Bufferização de resposta

O Bun faz grandes esforços para otimizar a performance de leitura do body da resposta. A maneira mais rápida de ler o body da resposta é usar um destes métodos:

  • response.text(): Promise<string>
  • response.json(): Promise<any>
  • response.formData(): Promise<FormData>
  • response.bytes(): Promise<Uint8Array>
  • response.arrayBuffer(): Promise<ArrayBuffer>
  • response.blob(): Promise<Blob>

Você também pode usar Bun.write para escrever o body da resposta em um arquivo em disco:

ts
import { write } from "bun";

await write("output.txt", response);

Detalhes de implementação

  • Pool de conexões é habilitado por padrão mas pode ser desabilitado por requisição com keepalive: false. O header "Connection: close" também pode ser usado para desabilitar keep-alive.
  • Uploads de arquivos grandes são otimizados usando a syscall sendfile do sistema operacional sob condições específicas:
    • O arquivo deve ser maior que 32KB
    • A requisição não deve estar usando um proxy
    • No macOS, apenas arquivos regulares (não pipes, sockets, ou dispositivos) podem usar sendfile
    • Quando estas condições não são atendidas, ou ao usar uploads S3/streaming, o Bun faz fallback para ler o arquivo para memória
    • Esta otimização é particularmente eficaz para requisições HTTP (não HTTPS) onde o arquivo pode ser enviado diretamente do kernel para a pilha de rede
  • Operações S3 automaticamente lidam com assinatura de requisições e merge de headers de autenticação

Nota: Muitos destes recursos são extensões específicas do Bun à API fetch padrão.

Bun by www.bunjs.com.cn edit