Skip to content

Bun implementa lo standard WHATWG fetch, con alcune estensioni per soddisfare le esigenze del JavaScript lato server.

Bun implementa anche node:http, ma fetch è generalmente consigliato invece.

Inviare una richiesta HTTP ​

Per inviare una richiesta HTTP, usa fetch

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

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

const text = await response.text(); // oppure response.json(), response.formData(), ecc.

fetch funziona anche con URL HTTPS.

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

Puoi anche passare a fetch un oggetto Request.

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

const response = await fetch(request);

Inviare una richiesta POST ​

Per inviare una richiesta POST, passa un oggetto con la proprietà method impostata a "POST".

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

body può essere una stringa, un oggetto FormData, un ArrayBuffer, un Blob e altro. Consulta la documentazione MDN per maggiori informazioni.

Proxy delle richieste ​

Per fare proxy di una richiesta, passa un oggetto con la proprietà proxy impostata a una stringa URL:

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

Puoi anche usare un formato oggetto per inviare header personalizzati al server 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",
    },
  },
});

Gli headers vengono inviati direttamente al proxy nelle richieste CONNECT (per target HTTPS) o nella richiesta proxy (per target HTTP). Se fornisci un header Proxy-Authorization, questo sovrascrive qualsiasi credenziale nell'URL del proxy.

Header personalizzati ​

Per impostare header personalizzati, passa un oggetto con la proprietà headers impostata a un oggetto.

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

Puoi anche impostare header usando l'oggetto Headers.

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

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

Corpi delle risposte ​

Per leggere il corpo della risposta, usa uno dei seguenti metodi:

  • response.text(): Promise<string>: Restituisce una promise che si risolve con il corpo della risposta come stringa.
  • response.json(): Promise<any>: Restituisce una promise che si risolve con il corpo della risposta come oggetto JSON.
  • response.formData(): Promise<FormData>: Restituisce una promise che si risolve con il corpo della risposta come oggetto FormData.
  • response.bytes(): Promise<Uint8Array>: Restituisce una promise che si risolve con il corpo della risposta come Uint8Array.
  • response.arrayBuffer(): Promise<ArrayBuffer>: Restituisce una promise che si risolve con il corpo della risposta come ArrayBuffer.
  • response.blob(): Promise<Blob>: Restituisce una promise che si risolve con il corpo della risposta come Blob.

Streaming dei corpi delle risposte ​

Puoi usare iteratori asincroni per fare streaming del corpo della risposta.

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

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

Puoi anche accedere più direttamente all'oggetto ReadableStream.

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

const stream = response.body;

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

Streaming dei corpi delle richieste ​

Puoi anche trasmettere in streaming i dati nei corpi delle richieste usando un 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,
});

Quando usi stream con HTTP(S):

  • I dati vengono trasmessi direttamente in rete senza memorizzare l'intero corpo in memoria
  • Se la connessione viene persa, lo stream sarà cancellato
  • L'header Content-Length non viene impostato automaticamente a meno che lo stream abbia una dimensione nota

Quando usi stream con S3:

  • Per richieste PUT/POST, Bun usa automaticamente upload multipart
  • Lo stream viene consumato in chunk e caricato in parallelo
  • Il progresso può essere monitorato attraverso le opzioni S3

Recuperare un URL con timeout ​

Per recuperare un URL con timeout, usa AbortSignal.timeout:

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

Annullare una richiesta ​

Per annullare una richiesta, usa un AbortController:

ts
const controller = new AbortController();

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

controller.abort();

Socket di dominio Unix ​

Per recuperare un URL usando un socket di dominio Unix, usa l'opzione 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 ​

Per usare un certificato client, usa l'opzione 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")],
  },
});

Validazione TLS personalizzata ​

Per personalizzare la validazione TLS, usa l'opzione checkServerIdentity in tls

ts
await fetch("https://example.com", {
  tls: {
    checkServerIdentity: (hostname, peerCertificate) => {
      // Restituisci un Error se il certificato non è valido
    },
  },
});

Questo è simile a come funziona nel modulo net di Node.

Disabilitare la validazione TLS ​

Per disabilitare la validazione TLS, imposta rejectUnauthorized a false:

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

Questo è particolarmente utile per evitare errori SSL quando si usano certificati autofirmati, ma questo disabilita la validazione TLS e dovrebbe essere usato con cautela.

Opzioni della richiesta ​

Oltre alle opzioni standard di fetch, Bun fornisce diverse estensioni:

ts
const response = await fetch("http://example.com", {
  // Controlla la decompressione automatica della risposta (default: true)
  // Supporta gzip, deflate, brotli (br) e zstd
  discomprime: true,

  // Disabilita il riutilizzo della connessione per questa richiesta
  keepalive: false,

  // Livello di log di debug
  verbose: true, // oppure "curl" per output più dettagliato
});

Supporto del protocollo ​

Oltre a HTTP(S), il fetch di Bun supporta diversi protocolli aggiuntivi:

URL S3 - s3:// ​

Bun supporta il recupero da bucket S3 direttamente.

ts
// Usando variabili d'ambiente per le credenziali
const response = await fetch("s3://my-bucket/path/to/object");

// O passano credenziali esplicitamente
const response = await fetch("s3://my-bucket/path/to/object", {
  s3: {
    accessKeyId: "YOUR_ACCESS_KEY",
    secretAccessKey: "YOUR_SECRET_KEY",
    region: "us-east-1",
  },
});

Nota: Solo i metodi PUT e POST supportano i corpi delle richieste quando si usa S3. Per i caricamenti, Bun usa automaticamente upload multipart per gli stream body.

Puoi leggere di più sul supporto S3 di Bun nella documentazione S3.

URL file - file:// ​

Puoi recuperare file locali usando il protocollo file::

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

Su Windows, i percorsi vengono normalizzati automaticamente:

ts
// Entrambi funzionano su Windows
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");

URL data - data: ​

Bun supporta lo schema URL data::

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

URL blob - blob: ​

Puoi recuperare blob usando URL creati da URL.createObjectURL():

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

Gestione degli errori ​

L'implementazione di fetch di Bun include diversi casi di errore specifici:

  • L'uso di un corpo della richiesta con metodi GET/HEAD genererà un errore (che è previsto per l'API fetch)
  • Il tentativo di usare sia le opzioni proxy che unix insieme genererà un errore
  • Fallimenti della validazione del certificato TLS quando rejectUnauthorized è true (o non definito)
  • Le operazioni S3 possono generare errori specifici relativi all'autenticazione o ai permessi

Gestione del Content-Type ​

Bun imposta automaticamente l'header Content-Type per i corpi delle richieste quando non esplicitamente fornito:

  • Per oggetti Blob, usa il type del blob
  • Per FormData, imposta il boundary multipart appropriato

Debug ​

Per aiutare con il debug, puoi passare verbose: true a fetch:

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

Questo stamperà gli header della richiesta e della risposta sul tuo terminale:

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 non fa parte dello standard web dell'API fetch ed è specifico di Bun.

Prestazioni ​

Prima che una richiesta HTTP possa essere inviata, deve essere eseguita la ricerca DNS. Questo può richiedere un tempo significativo, specialmente se il server DNS è lento o la connessione di rete è scarsa.

Dopo la ricerca DNS, il socket TCP deve essere connesso e l'handshake TLS potrebbe dover essere eseguito. Anche questo può richiedere un tempo significativo.

Dopo che la richiesta è completata, consumare il corpo della risposta può richiedere anche un tempo significativo e memoria.

In ogni fase, Bun fornisce API per aiutarti a ottimizzare le prestazioni della tua applicazione.

Prefetch DNS ​

Per prefetchare una voce DNS, puoi usare l'API dns.prefetch. Questa API è utile quando sai che dovrai connetterti a un host presto e vuoi evitare la ricerca DNS iniziale.

ts
import { dns } from "bun";

dns.prefetch("bun.com");

Cache DNS ​

Di default, Bun memorizza nella cache e deduplica le query DNS in memoria per fino a 30 secondi. Puoi vedere le statistiche della cache chiamando dns.getCacheStats():

Per saperne di più sulla cache DNS in Bun, consulta la documentazione sulla cache DNS.

Preconnettersi a un host ​

Per preconnetterti a un host, puoi usare l'API fetch.preconnect. Questa API è utile quando sai che dovrai connetterti a un host presto e vuoi iniziare la ricerca DNS iniziale, la connessione del socket TCP e l'handshake TLS presto.

ts
import { fetch } from "bun";

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

Nota: chiamare fetch immediatamente dopo fetch.preconnect non renderà la tua richiesta più veloce. La preconnessione aiuta solo se sai che dovrai connetterti a un host presto, ma non sei ancora pronto per fare la richiesta.

Preconnessione all'avvio ​

Per preconnetterti a un host all'avvio, puoi passare --fetch-preconnect:

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

Questo è un po' come <link rel="preconnect"> in HTML.

Questa funzionalità non è ancora implementata su Windows. Se sei interessato a usare questa funzionalità su Windows, per favore apri un issue e possiamo implementare il supporto per essa su Windows.

Connection pooling e HTTP keep-alive ​

Bun riutilizza automaticamente le connessioni allo stesso host. Questo è noto come connection pooling. Questo può ridurre significativamente il tempo necessario per stabilire una connessione. Non devi fare nulla per abilitare questo; è automatico.

Limite di connessioni simultanee ​

Di default, Bun limita il numero massimo di richieste fetch simultanee a 256. Lo facciamo per diversi motivi:

  • Migliora la stabilità generale del sistema. I sistemi operativi hanno un limite superiore sul numero di socket TCP aperti simultaneamente, di solito nelle migliaia. Avvicinarsi a questo limite fa comportare in modo strano l'intero computer. Le applicazioni si bloccano e crashano.
  • Incoraggia il riutilizzo delle connessioni HTTP Keep-Alive. Per richieste HTTP di breve durata, il passaggio più lento è spesso la configurazione iniziale della connessione. Riutilizzare le connessioni può far risparmiare molto tempo.

Quando il limite viene superato, le richieste vengono accodate e inviate non appena termina la prossima richiesta.

Puoi aumentare il numero massimo di connessioni simultanee tramite la variabile d'ambiente BUN_CONFIG_MAX_HTTP_REQUESTS:

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

Il valore massimo per questo limite è attualmente impostato a 65.336. Il numero di porta massimo è 65.535, quindi è abbastanza difficile per qualsiasi computer superare questo limite.

Buffering della risposta ​

Bun fa di tutto per ottimizzare le prestazioni della lettura del corpo della risposta. Il modo più veloce per leggere il corpo della risposta è usare uno di questi metodi:

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

Puoi anche usare Bun.write per scrivere il corpo della risposta su un file su disco:

ts
import { write } from "bun";

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

Dettagli dell'implementazione ​

  • Il connection pooling è abilitato di default ma può essere disabilitato per richiesta con keepalive: false. L'header "Connection: close" può anche essere usato per disabilitare keep-alive.
  • I caricamenti di file grandi sono ottimizzati usando la syscall sendfile del sistema operativo sotto condizioni specifiche:
    • Il file deve essere più grande di 32KB
    • La richiesta non deve usare un proxy
    • Su macOS, solo file regolari (non pipe, socket o dispositivi) possono usare sendfile
    • Quando queste condizioni non sono soddisfatte, o quando si usano caricamenti S3/streaming, Bun legge il file in memoria
    • Questa ottimizzazione è particolarmente efficace per richieste HTTP (non HTTPS) dove il file può essere inviato direttamente dal kernel allo stack di rete
  • Le operazioni S3 gestiscono automaticamente la firma delle richieste e l'unione degli header di autenticazione

Nota: Molte di queste funzionalità sono estensioni specifiche di Bun all'API fetch standard.

Bun a cura di www.bunjs.com.cn