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
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.
const response = await fetch("https://example.com");Você também pode passar para fetch um objeto Request.
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".
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:
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:
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.
const response = await fetch("http://example.com", {
headers: {
"X-Custom-Header": "value",
},
});Você também pode definir headers usando o objeto Headers.
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 objetoFormData.response.bytes(): Promise<Uint8Array>: Retorna uma promise que resolve com o body da resposta como umUint8Array.response.arrayBuffer(): Promise<ArrayBuffer>: Retorna uma promise que resolve com o body da resposta como umArrayBuffer.response.blob(): Promise<Blob>: Retorna uma promise que resolve com o body da resposta como umBlob.
Streaming de bodies de resposta
Você pode usar iteradores assíncronos para fazer stream do body da resposta.
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.
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:
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-Lengthnã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:
const response = await fetch("http://example.com", {
signal: AbortSignal.timeout(1000),
});Cancelando uma requisição
Para cancelar uma requisição, use um AbortController:
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:
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:
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
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:
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:
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.
// 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::
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();No Windows, caminhos são automaticamente normalizados:
// 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::
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():
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
proxyeunixjuntas 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 otypedo blob - Para
FormData, define o boundary multipart apropriado
Debugging
Para ajudar com debugging, você pode passar verbose: true para fetch:
const response = await fetch("http://example.com", {
verbose: true,
});Isto imprimirá os headers de requisição e resposta no seu terminal:
[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: 648Nota: 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.
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.
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:
bun --fetch-preconnect https://bun.com ./my-script.tsIsto é 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:
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun ./my-script.tsO 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:
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
sendfiledo 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.