Node.js Fetch API: Det du missar i varje tutorial (guide 2026)

Senast uppdaterad May 14, 2026
Node.js Fetch API: Det du missar i varje tutorial (guide 2026)
AI-sammanfattning
Sluta förlita dig på enkla fetch-anrop i produktion. Lär dig hantera timeouts, HTTP-fel, retry-logik och anslutningspoolning i Node.js för 2026.

Varje Node.js fetch-handledning lär dig await fetch(url) och stannar där. Sedan sväljer din produktionsapp tyst ett 500-fel, en begäran hänger i 90 sekunder utan timeout, och du får ägna en fredagskväll åt att felsöka något som borde ha varit uppenbart.

Jag har byggt interna verktyg och datapipelines på Thunderbit ett tag nu, och jag kan säga en sak: glappet mellan "fetch funkar i min handledning" och "fetch funkar i produktion" är där det mesta av smärtan bor. En utvecklare på Reddit formulerade det perfekt: "när du går till produktion inser du att du behöver något mer robust än den inbyggda fetch."

En annan erkände: "Jobbat i 3 år som webbutvecklare, idag lärde jag mig att fetch API:s catch-block INTE är för HTTP-fel." Den här guiden går igenom de fem saker som de flesta handledningar hoppar över — fel-fällan, AbortController-timeouts, retry-logik, återanvändning av anslutningar och när du bör gå vidare från fetch för strukturerad datautvinning. Om du någon gång har sett ett fetch-anrop misslyckas tyst i produktion är den här för dig.

nodejs-fetch-error-handling-flowchart.png

Vad är Node.js Fetch API?

Node.js Fetch API är det inbyggda, webbläsarkompatibla sättet att göra HTTP-förfrågningar (GET, POST, PUT, DELETE osv.) från Node.js — utan att installera Axios, node-fetch eller något annat paket. Om du har använt fetch() i webbläsaren känner du redan igen syntaxen. Nu fungerar samma API på servern.

Här är den snabba versionshistoriken:

MilstolpeNode-versionVad som hände
Experimentell fetch-flaggav17.5.0 / v16.15.0fetch lades till bakom --experimental-fetch
Standard global fetchv18.0.0Experimentell fetch blev tillgänglig globalt, driven av Undici
Stabil fetchv21.0.0Inte längre experimentell
Produktionsbaslinje 2026v22 LTS / v24 LTSRekommenderas för produktion; v20 är nu EOL

Under huven drivs Nodes fetch av Undici — en högpresterande HTTP-klient byggd specifikt för Node.js. Den bygger inte på den äldre inbyggda http-modulen. Den praktiska fördelen: du får ett modernt, Promise-baserat HTTP-API som fungerar på samma sätt i din webbläsarkod, din Express-backend, din serverless-funktion och dina CLI-skript.

Varför Node.js Fetch API är viktigt för dina projekt

Före Node 18 började varje nytt projekt med samma ritual: npm install axios eller npm install node-fetch. År 2026, om ditt projekt kör på en underhållen Node LTS, kräver grundläggande HTTP-förfrågningar inga beroenden alls. Det är en verklig vinst för paketstorlek, säkerhet i leveranskedjan och onboarding (frontend- och backendutvecklare delar äntligen samma API).

Här är var native fetch glänser:

ScenarioVarför native fetch fungerar braAtt tänka på i produktion
Express/Fastify-backend som anropar REST-API:erBekant async/await, inget beroendeLägg till timeout och kontroller av response.ok
Serverless-funktioner (Lambda, Vercel osv.)Litet cold-start-avtryck, ingen paketinstallationHåll timeout under plattformens maxgräns
CLI-skript och automatiseringEnkla GET/POST utan projektuppsättningLägg till retry/backoff för instabila API:er
Webhook-leverans eller vidarebefordranStandardiserade HTTP-metoder och headersFörsök inte blint igen med icke-idempotenta POST-anrop
Rapporter och dashboardsBra för att hämta JSON från API:erAnvänd paginering och anslutningspooling i loopar
Kommunikation mellan mikrotjänsterFungerar för enkla interna HTTP-anropÖverväg Got eller Undici direkt för retry, hooks eller HTTP/2

För nya Node 22+-projekt är native fetch det rimliga förstahandsvalet — om du inte vet att du behöver funktioner det inte erbjuder (interceptors, inbyggd retry, HTTP/2 osv.). npm-nedladdningssiffrorna visar en marknad i förändring: node-fetch drar fortfarande in cirka 144,9 miljoner veckovisa nedladdningar, men mycket av det är legacy och transitiva beroenden. Axios ligger på cirka 108,6 miljoner, Undici på cirka 106 miljoner, Got på cirka 36 miljoner och Ky på cirka 5,6 miljoner. Trenden är tydlig: native fetch är den nya baslinjen, och tredjepartsklienter används för specifika behov.

Native Fetch vs node-fetch vs Axios vs Got vs Ky: Beslutsmatrisen för 2026

Den vanligaste frågan jag ser i utvecklarforum: "Vilken HTTP-klient ska jag använda i Node.js?" En Reddit-användare sammanfattade det så här: "varför importera ett bibliotek… när språket/ramverket redan har funktionaliteten inbyggd?" Bra poäng — men svaret beror på vad du behöver.

http-client-libraries-comparison.png

FunktionNative fetchnode-fetch v3axiosgot v15ky v2
Node.js-version≥18 (rekommenderas 22/24 LTS)≥12.20Brett stöd≥22≥22
Installation krävsNejJaJaJaJa
Stöd för ESM + CJSBåda (globalt)Endast ESM (v3)BådaEndast ESMEndast ESM
Automatisk avvisning på 4xx/5xxNejNejJaJaJa
Inbyggd retryNejNejNejJaJa
Request interceptorsNejNejJaJa (hooks)Ja (hooks)
Stöd för streamingWeb ReadableStreamJaBegränsatKraftfulla Node streamsBaserat på fetch
Storlek/installationsavtryck0 KB~107 KB, 3 beroenden~2,8 MB, 4 beroenden~355 KB, 12 beroenden~405 KB, 0 beroenden
HTTP/2-stödVia Undici dispatcherNejNejJaNej (fetch-wrapper)

En snabb notis om ESM/CJS-problematiken: node-fetch v3 är endast ESM, vilket bröt många projekt som använde require(). Native fetch är global — det fungerar i både CJS- och ESM-filer utan importkrångel. Om du sitter fast på node-fetch v2 på grund av CommonJS löser native fetch det problemet helt.

Och om tidiga stabilitetsfrågor: ja, det fanns riktiga buggar i Node 18:s första fetch-implementation. En utvecklare på Reddit nämnde: "Hade en galen bugg med native node 18 fetch nyligen så vi var tvungna att konvertera vår app." Det var 2023. År 2026, med Node 22 och 24 LTS, är de problemen lösta. Native fetch är redo för produktion.

När du bör hålla dig till native fetch

Välj native fetch när:

  • Ditt projekt kör på Node 22 LTS eller Node 24 LTS.
  • Förfrågningarna är enkla REST-anrop (GET, POST, PUT, DELETE).
  • Du är villig att lägga till en liten wrapper för response.ok, JSON-parsning, timeouts och retry.
  • Du vill ha noll beroenden och mindre oro för leveranskedjan.
  • Du värdesätter att webbläsar- och server-API:er beter sig likadant.
  • Du jobbar i serverless- eller edge-miljöer där inbyggda API:er föredras.

När Axios, Got eller Ky är mer rimliga

Axios är rätt val när ditt team förlitar sig på request/response-interceptors (t.ex. automatisk uppdatering av autentiseringstoken, tenant-headers, centraliserad loggning), när du vill att HTTP-fel ska avvisa som standard, eller när du behöver bakåtkompatibilitet med äldre Node-miljöer.

Got är byggt för Node-tjänster med hög genomströmning som behöver inbyggd retry, hooks, avancerade timeout-faser, streams, hjälpfunktioner för paginering, Unix sockets, proxy-/cacheflöden eller HTTP/2-stöd. Det är schweiziska armékniven för HTTP-arbete enbart i Node.

Ky är den bästa mittpunkten om du gillar fetchs enkelhet men vill ha mindre boilerplate — det lägger till retry, timeout, hooks och HTTPError i ett litet paket utan beroenden.

Hur man gör GET-förfrågningar med Node.js Fetch API

En GET-förfrågan med async/await ser ut så här:

const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const post = await response.json();
console.log(post.title);
// → "sunt aut facere repellat provident occaecati excepturi optio reprehenderit"

Och om du föredrar .then()-kedjan:

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => response.json())
  .then(post => console.log(post.title))
  .catch(error => console.error(error));

Båda fungerar. Men ingen av dem är ännu säker nog för produktion (mer om det om en stund).

Response-läsare du bör känna till:

MetodAnvänd när
response.json()Servern returnerar JSON
response.text()Servern returnerar HTML, vanlig text, CSV eller Markdown
response.arrayBuffer()Du behöver binär data (bilder, filer)
response.bodyDu behöver streaming-/chunk-bearbetning

Ett bättre mönster — ett som faktiskt kontrollerar fel:

async function getPost(id) {
  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  if (!response.ok) {
    throw new Error(`HTTP ${response.status} ${response.statusText}`);
  }
  return response.json();
}

const post = await getPost(1);
console.log(post.title);

Den där raden if (!response.ok) är skillnaden mellan en handledning och produktionskod. Och därmed kommer vi till den största fällan.

Hur man skickar POST-förfrågningar med Node.js Fetch API

POST-förfrågningar följer samma mönster — du sätter bara metod, headers och body:

const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    title: 'Node fetch-guide',
    body: 'Production fetch behöver felhantering.',
    userId: 1,
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const created = await response.json();
console.log(created.id); // → 101

Skicka andra typer av förfrågningar (PUT, DELETE, PATCH)

PUT, PATCH och DELETE använder exakt samma struktur med ett annat method-värde:

// PUT — full ersättning
await fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ id: 1, title: 'Ersatt', body: 'Full ersättning', userId: 1 }),
});

// PATCH — delvis uppdatering
await fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Delvis uppdatering' }),
});

// DELETE
await fetch('https://jsonplaceholder.typicode.com/posts/1', {
  method: 'DELETE',
});

Fällan med Express body-parser: Om du POST:ar JSON till en Express-server och req.body kommer tillbaka som undefined, är lösningen nästan alltid denna: använd express.json(), inte express.urlencoded(). Servern behöver express.json()-middleware före din route för att tolka bodies med Content-Type: application/json. Det här är en av de vanligaste Stack Overflow-frågorna om Express, och det ställer till det för folk gång på gång.

import express from 'express';
const app = express();
app.use(express.json()); // ← Den här behöver du för JSON-POST-bodies
app.post('/api/posts', (req, res) => {
  res.json({ received: req.body });
});

Fel-fällan i fetch() som saboterar produktionsappar

fetch-error-handling-flowchart.png

Härifrån kommer de flesta fetch-buggar i produktion.

fetch() avvisar inte sitt Promise vid HTTP 4xx- eller 5xx-fel. Det avvisar bara vid fel på nätverksnivå — DNS-fel, inget internet, avbrutna förfrågningar. Om servern returnerar ett 403 Forbidden eller ett 500 Internal Server Error betraktar fetch det som ett lyckat svar. Ditt .catch()-block körs aldrig. Ditt try/catch fångar det aldrig. Din kod bearbetar glatt vad än servern skickade tillbaka.

MDN:s dokumentation säger detta tydligt, men de flesta handledningar går förbi det. Resultatet? Kod som ser helt okej ut men sväljer fel i tysthet:

try {
  const response = await fetch('https://api.example.com/private');
  const data = await response.json(); // ← Det här körs även vid 403
  console.log('Ser lyckat ut:', data);
} catch (error) {
  // Bara fel på nätverksnivå hamnar här
  console.error('Fångat:', error);
}

Här är en snabb genomgång av vad varje mönster faktiskt fångar:

MönsterFångar nätverksfelFångar 4xx/5xxParsar JSON säkertÅteranvändbart
.then(res => res.json())Ja (via .catch())NejIngen kontroll av content-typeNej
try/catch med await fetch()JaNejIngen kontroll av content-typeNej
Manuell if (!res.ok) per anropJaJaBeror på varje anropDelvis
Anpassad fetchJSON()-wrapperJaJaJaJa

Bygg en återanvändbar fetchJSON()-wrapper

Bygg en wrapper. Importera den överallt. Sluta kopiera if (!response.ok) till varje fil:

export class HTTPError extends Error {
  constructor(message, { status, statusText, url, body }) {
    super(message);
    this.name = 'HTTPError';
    this.status = status;
    this.statusText = statusText;
    this.url = url;
    this.body = body;
  }
}

export async function fetchJSON(url, options = {}) {
  const response = await fetch(url, {
    headers: {
      Accept: 'application/json',
      ...options.headers,
    },
    ...options,
  });

  const contentType = response.headers.get('content-type') || '';
  const isJSON = contentType.includes('application/json');
  const body = isJSON ? await response.json().catch(() => null) : await response.text();

  if (!response.ok) {
    throw new HTTPError(`HTTP ${response.status} ${response.statusText}`, {
      status: response.status,
      statusText: response.statusText,
      url: response.url,
      body,
    });
  }

  return body;
}

Nu, när servern returnerar en 403:

try {
  const data = await fetchJSON('https://api.example.com/private');
} catch (error) {
  if (error instanceof HTTPError) {
    console.error(`Servern returnerade ${error.status}:`, error.body);
  } else {
    console.error('Nätverksfel eller annat fel:', error);
  }
}

Felet bär med sig statuskod, response body och URL — allt du behöver för loggning, larm eller användarvända meddelanden. Importera det här en gång, använd det överallt.

AbortController och timeouts: Produktionsmönstret för Node.js Fetch API

request-retry-pooling-flowchart.png

Utan timeout hänger ett fetch-anrop för evigt när fjärrservern blir tyst. Din Express-route blockeras. Din Lambda bränner sin exekveringsbudget. Ditt skript bara… sitter där.

Jag kollade de främsta sökresultaten: inte en enda Node.js-specifik fetch-handledning täcker avbrytning eller timeouts. Ändå är timeouts en av de vanligaste anledningarna till att utvecklare håller fast vid Axios eller Got. En Reddit-tråd heter bokstavligen "Node fetch does not timeout".

Använd AbortSignal.timeout() (Node 18.11+)

Det enklaste sättet — ett extra alternativ:

try {
  const response = await fetch('https://api.example.com/data', {
    signal: AbortSignal.timeout(5000), // 5 sekunder
  });

  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const data = await response.json();
  console.log(data);
} catch (error) {
  if (error.name === 'TimeoutError') {
    console.error('Begäran tog längre än 5 sekunder och timade ut.');
  } else {
    throw error;
  }
}

Obs: AbortSignal.timeout() kastar en TimeoutError, inte en AbortError. Det här är en detalj som även vissa erfarna utvecklare blandar ihop.

Manuell timeout med AbortController

För mer kontroll — eller om du behöver avbryta en begäran baserat på användarens handling, inte bara en timer:

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch('https://api.example.com/data', {
    signal: controller.signal,
  });
  const data = await response.json();
  console.log(data);
} catch (error) {
  if (error.name === 'AbortError') {
    console.error('Begäran avbröts manuellt.');
  } else {
    throw error;
  }
} finally {
  clearTimeout(timeout);
}

Hantera AbortError vs TimeoutError

Den här skillnaden spelar roll för loggning och användarvända meddelanden:

AvbrytningsvägFelnamn i catch-blocket
AbortSignal.timeout(ms)TimeoutError
controller.abort()AbortError
DNS-/nätverksfelVanligtvis TypeError: fetch failed

Här är ett praktiskt scenario — en Express-route som anropar ett externt API och måste svara inom 3 sekunder:

app.get('/dashboard', async (req, res, next) => {
  try {
    const data = await fetchJSON('https://api.example.com/report', {
      signal: AbortSignal.timeout(3000),
    });
    res.json(data);
  } catch (error) {
    if (error.name === 'TimeoutError') {
      res.status(504).json({ error: 'Uppströms API timade ut' });
      return;
    }
    next(error);
  }
});

Utan det här mönstret skulle ett långsamt uppströms API blockera hela din route tills klienten ger upp.

Retry-logik och återanvändning av anslutningar: Gör Node.js Fetch API produktionsklart

Native fetch har ingen inbyggd retry. Ett nätverksglapp eller en tillfällig 503 betyder att begäran helt enkelt misslyckas. För de flesta läsoperationer i produktion är det inte acceptabelt.

En komponerbar retry-wrapper med exponentiell backoff

Det här är medvetet kort — ungefär 10 rader faktisk logik:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

export async function fetchWithRetry(url, options = {}, retries = 2) {
  for (let attempt = 0; ; attempt++) {
    try {
      const response = await fetch(url, options);
      if (response.ok || ![408, 429, 500, 502, 503, 504].includes(response.status)) {
        return response;
      }
      if (attempt >= retries) return response;
    } catch (error) {
      if (attempt >= retries) throw error;
    }
    await wait(250 * 2 ** attempt); // 250 ms, 500 ms, 1000 ms...
  }
}

När du bör retry:a (och när du inte ska)

  • Retry:a: Idempotenta GET- och HEAD-begäranden, tillfälliga statuskoder (408, 429, 500, 502, 503, 504), nätverksglapp.
  • Retry:a inte: Icke-idempotenta POST-begäranden som skapar poster, debiterar pengar eller utlöser sidoeffekter — om du inte använder idempotency keys.
  • Respektera Retry-After: För 429 (hastighetsbegränsning) och 503 (tjänsten otillgänglig), kontrollera Retry-After-headern innan du backar av.

Om du hellre inte vill bygga egen retry-logik är Ky en lättviktig fetch-wrapper som lägger till retry, timeout, hooks och HTTPError direkt ur lådan — utan beroenden.

Återanvändning av anslutningar med Undicis Agent och Pool

För loopar med hög genomströmning — skrapa hundratals sidor, anropa ett API i batch, polla en tjänst — sparar återanvändning av TCP-anslutningar betydande tid. Varje ny anslutning innebär en ny DNS-uppslagning, TCP-handshake och, för HTTPS, TLS-förhandling.

Eftersom Nodes fetch drivs av Undici kan du skicka in en anpassad dispatcher:

import { Agent } from 'undici';

const agent = new Agent({
  keepAliveTimeout: 10_000,
  keepAliveMaxTimeout: 60_000,
});

const response = await fetch('https://api.example.com/data', {
  dispatcher: agent,
});

För ännu mer kontroll med en specifik origin:

import { Pool } from 'undici';

const pool = new Pool('https://api.example.com', { connections: 10 });

const response = await fetch('https://api.example.com/data', {
  dispatcher: pool,
});

// När du är klar:
await pool.close();

Undici README:s benchmarkresultat visar att återanvändning av anslutningar och pooling kan förbättra genomströmningen dramatiskt — undici - dispatch låg på cirka 22 234 förfrågningar/sekund jämfört med undici - fetch på cirka 5 904 förfrågningar/sekund i deras lokala benchmark. Verkliga siffror varierar, men riktningen är tydlig: om du gör många anrop till samma origin spelar pooling roll.

En sak till: konsumera eller avbryt alltid response bodies. Oanvända bodies kan orsaka resursläckor i Nodes HTTP-internals.

Strömmande svar med Node.js Fetch API

Stora filnedladdningar, chunkade JSON-flöden, server-sent events, LLM-utdata — det här är fall där det slösar tid och minne att vänta på hela svaret innan du bearbetar det. Streaming låter dig hantera data medan den kommer in.

streaming-data-chunking-process.png

Node 18+ inkluderar webbläsarkompatibel ReadableStream. Så här streamar du ett newline-delimited JSON-svar och bearbetar varje rad när den anländer:

const response = await fetch('https://example.com/large-file.ndjson');
if (!response.ok) throw new Error(`HTTP ${response.status}`);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { value, done } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });

  let newlineIndex;
  while ((newlineIndex = buffer.indexOf('\n')) >= 0) {
    const line = buffer.slice(0, newlineIndex).trim();
    buffer = buffer.slice(newlineIndex + 1);
    if (line) {
      const item = JSON.parse(line);
      console.log('Bearbetat:', item.id);
    }
  }
}

För enklare textstreaming (t.ex. att skicka LLM-utdata till stdout):

const response = await fetch('https://example.com/stream');
const reader = response.body.getReader();
const decoder = new TextDecoder();

for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  process.stdout.write(decoder.decode(value, { stream: true }));
}

Streaming är ett område där native fetch och Got båda är starka. Axios streamingstöd är mer begränsat.

När fetch() når sina gränser: Strukturerad webbscraping med API:er

Vid någon punkt är fetch inte längre flaskhalsen. Det verkliga problemet blir: "Jag har HTML — vad nu?"

web-scraping-vs-ai-extraction-api-comparison.png

Fetch är en HTTP-klient — den hämtar bytes, text, JSON eller HTML. Den har ingen förståelse för ett produktkort, ett pris, ett betyg eller en kontakttabell. För strukturerad webbscraping ser den typiska råa stacken ut så här:

  1. fetch() för att ladda ner HTML
  2. Cheerio (eller liknande) för att välja element med CSS-selektorer
  3. Egen logik för paginering
  4. JavaScript-rendering när sidor renderas på klientsidan
  5. Proxy-/anti-bot-/CAPTCHA-hantering
  6. Underhåll av selektorer varje gång sidans layout ändras

Här är ett typiskt exempel med fetch + Cheerio — ungefär 15 rader för att skrapa produkttitlar:

import * as cheerio from 'cheerio';

const response = await fetch('https://example-store.com/products');
if (!response.ok) throw new Error(`HTTP ${response.status}`);

const html = await response.text();
const $ = cheerio.load(html);

const products = $('.product-card')
  .map((_, el) => ({
    name: $(el).find('.product-title').text().trim(),
    price: $(el).find('.price').text().trim(),
    url: new URL($(el).find('a').attr('href'), response.url).href,
  }))
  .get();

console.log(products);

Det här fungerar för stabila sidor med förutsägbar HTML. Det blir snabbt skört — JavaScript-renderat innehåll, ändrade klassnamn, anti-bot-mekanismer och paginering lägger till komplexitet.

Thunderbits öppna API: Från rå HTML till strukturerad data i ett enda anrop

Det är här en annan typ av verktyg blir användbar. På Thunderbit byggde vi ett API-lager som hanterar de jobbiga delarna — JavaScript-rendering, anti-bot-skydd, layoutändringar — så att du kan fokusera på den data du faktiskt vill ha.

Distill API (POST /distill): Konverterar vilken URL som helst till ren Markdown. Användbart för att mata LLM:er, bygga kunskapsbaser eller göra innehållsanalys — ingen HTML-parser behövs.

Extract API (POST /extract): Definiera ett JSON Schema som beskriver den strukturerade data du vill ha (produktnamn, pris, betyg), så extraherar AI:n den. Inga CSS-selektorer, inget som går sönder när layouter ändras.

Här är samma produktskrapningsuppgift med Thunderbits Extract API — anropad med native fetch:

const response = await fetch('https://openapi.thunderbit.com/openapi/v1/extract', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.THUNDERBIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: 'https://example-store.com/products',
    renderMode: 'basic',
    schema: {
      type: 'object',
      properties: {
        products: {
          type: 'array',
          items: {
            type: 'object',
            properties: {
              name: { type: 'string', description: 'Produktnamn' },
              price: { type: 'string', description: 'Visat produktpris' },
              rating: { type: 'number', description: 'Genomsnittligt kundbetyg' },
            },
            required: ['name', 'price'],
          },
        },
      },
      required: ['products'],
    },
  }),
});

if (!response.ok) throw new Error(`Thunderbit API: ${response.status}`);
const result = await response.json();
console.log(result.data);

Jämförelsen: ungefär 15 rader med fetch + Cheerio (plus sköra selektorer) jämfört med ett enda API-anrop som returnerar ren JSON. För batchjobb stöder Thunderbit upp till 50 URL:er per batch extract-anrop och upp till 100 URL:er per batch distill-anrop.

Thunderbit är inte en ersättning för fetch — fetch är transporten. Thunderbit är extraktionslagret du använder när rå HTML-parsing blir det verkliga problemet. Om du är nyfiken på prissättningen ger gratisnivån dig 600 API-enheter att experimentera med, och betalda planer börjar på 6 dollar/månad. Du kan också kolla in Thunderbit Chrome Extension för kodfri extraktion direkt i webbläsaren.

För mer om strukturerade scrapingmetoder täcker våra guider om bästa verktygen för datautvinning, hur man skapar en web scraper och skrapa data från webbplats till Excel specifika arbetsflöden i detalj.

Snabbreferens: Fusklapp för Node.js Fetch API

Det här avsnittet är tänkt att bokmärkas. Kom tillbaka när du behöver ett mönster att kopiera och klistra in.

MönsterKodsnutt
Grundläggande GETconst res = await fetch(url); const data = await res.json();
Grundläggande POSTawait fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
Kontroll av HTTP-felif (!res.ok) throw new Error(\\HTTP ${res.status}\);
Timeout (enkelt)await fetch(url, { signal: AbortSignal.timeout(5000) });
Manuell avbrytningconst c = new AbortController(); setTimeout(() => c.abort(), 5000); await fetch(url, { signal: c.signal });
Statuskoder för retryRetry:a 408, 429, 500, 502, 503, 504. Retry:a inte POST blint.
JSON-wrapperAnvänd fetchJSON() för att kontrollera ok, tolka content type och kasta HTTPError.
Anslutningspoolimport { Pool } from 'undici'; const pool = new Pool(origin, { connections: 10 }); fetch(url, { dispatcher: pool });
Streama chunkarconst reader = res.body.getReader(); loopa över await reader.read()
Strukturerad extraktionAnvänd Thunderbit Extract API när målet är fält från en webbsida, inte rå HTML.

Slutsats och viktiga lärdomar

Native fetch i Node.js är redo för produktion år 2026 — ingen node-fetch krävs för nya projekt, inget standardberoende av Axios behövs. Men rå fetch() ensam är inte en produktionsstrategi för HTTP.

De fem saker som de flesta handledningar hoppar över — och som den här guiden har täckt:

  1. Fel-fällan: fetch() kastar inte på 4xx/5xx. Kontrollera alltid response.ok eller använd en wrapper som fetchJSON().
  2. Timeouts: Använd AbortSignal.timeout() för enkla fall. AbortSignal.timeout() kastar TimeoutError; manuell controller.abort() kastar AbortError.
  3. Retry-logik: Inte inbyggd. Lägg till exponentiell backoff för idempotenta anrop och tillfälliga fel. Eller använd Ky för fetch med liknande beteende direkt.
  4. Återanvändning av anslutningar: För loopar med hög genomströmning, använd Undicis Agent eller Pool via dispatcher-alternativet.
  5. Strukturerad extraktion: När du behöver data från webbsidor (inte bara rå HTML), överväg ett extraktions-API som Thunderbit i stället för att underhålla sköra CSS-selektorer.

Beslutsmatrisen i en mening: använd native fetch för de flesta projekt, Axios för interceptors, Got för inbyggd retry och HTTP/2, Ky för fetch med bättre standardinställningar och Thunderbits API när dina fetch-baserade scraping-skript blir för komplexa att underhålla.

Prova Thunderbit för strukturerad datautvinning

Prova mönstren i den här guiden. Och om du vill se hur Thunderbit hanterar strukturerad extraktion är gratisnivån ett bra ställe att börja på — eller titta på en genomgång på Thunderbits YouTube-kanal.

Prova Thunderbit för AI-webbskrapning Get Started Free

Vanliga frågor

1. Är fetch inbyggt i Node.js eller behöver jag installera det?

Fetch är inbyggt i Node.js 18 och senare — ingen installation behövs. Det blev stabilt i Node 21 och stöds fullt ut i Node 22 LTS och Node 24 LTS. För äldre Node-versioner kan du använda npm-paketet node-fetch, men nya projekt bör sikta på en underhållen LTS-version.

2. Kastar fetch ett fel vid 404- eller 500-svar?

Nej. Fetch avvisar bara sitt Promise vid fel på nätverksnivå (DNS-fel, ingen anslutning, avbrutna förfrågningar). HTTP-svar som 404, 403 och 500 löses normalt med response.ok === false. Du måste kontrollera response.ok eller response.status explicit — eller använda en wrapper som fetchJSON()-funktionen som visas i den här guiden.

3. Hur lägger jag till en timeout i fetch i Node.js?

Det enklaste sättet är AbortSignal.timeout(ms), tillgängligt i Node 18.11+: await fetch(url, { signal: AbortSignal.timeout(5000) }). Det kastar en TimeoutError om begäran överstiger 5 sekunder. För mer kontroll kan du skapa en AbortController manuellt och anropa controller.abort() från en setTimeout. Fånga AbortError för det manuella mönstret och TimeoutError för AbortSignal.timeout().

4. Kan jag använda fetch för web scraping i Node.js?

Ja, men fetch returnerar bara rå HTML. Du behöver en parser som Cheerio för att extrahera specifika element, plus egen logik för paginering, JavaScript-renderade sidor och anti-bot-mekanismer. För strukturerad datautvinning i skala — där du vill ha ren JSON med produktnamn, priser eller kontaktinformation — överväg Thunderbits Extract API, som använder AI för att returnera strukturerad data utan CSS-selektorer eller layoutberoende kod.

5. Bör jag byta från Axios till native fetch år 2026?

För nya projekt på Node 22+ är native fetch ett starkt förstahandsval. Det är utan beroenden, Promise-baserat och delar samma API som webbläsarens fetch. Behåll Axios om du förlitar dig på request/response-interceptors, standardmässig avvisning på HTTP-fel eller behöver bakåtkompatibilitet med äldre Node-versioner. Båda är giltiga val — beslutet beror på vilka funktioner ditt projekt faktiskt använder.

Läs mer

Fawad Khan
Fawad Khan
Fawad skriver för sitt levebröd, och ärligt talat tycker han ganska mycket om det. Han har ägnat år åt att ta reda på vad som gör en text rad att fastna — och vad som får läsare att scrolla vidare. Fråga honom om marknadsföring, så kan han prata i timmar. Fråga honom om carbonara, så pratar han ännu längre.
Innehåll

Samla in en webbsida genom att bara fråga

Säg vad du behöver på enkel engelska. Eller ännu bättre, säg ingenting alls.

Prova Thunderbit gratis
Extrahera data med AI
Överför enkelt data till Google Sheets, Airtable eller Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week