Node.js download souboru

Potřebuji v Node.js aplikaci stáhnout soubor na server pomocí http dotazu. Možností je opravdu hodně a není snadné si vybrat.

Na první nástřel nepotřebujeme žádný balíček a můžeme použít pouze prostředky Node.js:

const fs = require('fs');
const https = require('https');

// URL of the image
const url = 'GFG.jpeg';

https.get(url,(res) => {
	// Image will be stored at this path
	const path = `${__dirname}/files/img.jpeg`;
	const filePath = fs.createWriteStream(path);
	res.pipe(filePath);
	filePath.on('finish',() => {
		filePath.close();
		console.log('Download Completed');
	})
})

Nemáme zde ale ošetřeny spousty náležitostí jako ošetření přesměrování na volaném serveru, timeout, apod.

Na to existuje spousta balíčků, které si pro přehlednost uložíme do tabulky:

Node.js download NPM

 HvězdStáříVelikostDep.Sp.
Axios950008 let446 kB24
Superagent1609111 let531 kB118
Got117798 let249 kB132
Node-fetch77828 let107 kB35
Bent21655 let26,7 kB31
Needle149611 let259 kB31
Ky-universal5443 roky6,85 kB21
Data k 8/2022; Hvězd: počet starts na Github.com; Dependencies produkční verze; Velikost: nekomprimováno; Dep: Dependencies; Sp: Spolupracovníků

Nakonec jsem se rozhodl tyto moduly nepoužívat. Pro moje účely jsou zbytečné, protože Node.js samo o sobě nabízí nástroje na stahování souborů. Je k tomu sice málo dokumentace a není to úplně srozumitelné, ale funguje to. Pro inspiraci zveřejňuji svůj funkční kód:

async #getByNodeFetch(url, file, timeoutMs = 1500) {
    const util = require('util');
    const streamPipeline = util.promisify(require('stream').pipeline);

    // by npm fetch
    const AbortController = globalThis.AbortController; // || (await import('abort-controller'));
    const controller = new AbortController();
    const timeout = setTimeout(() => {
      controller.abort();
    }, timeoutMs);
    let res;
    //TODO zřejmě AbortSignal není zatím implementován, tedy nelze timeout --> const res = await fetch(url, { signal: AbortSignal.timeout(30) });
    try {
      res = await fetch(url, { method: 'GET', signal: controller.signal }); // takto timeout funguje - signal: AbortSignal.timeout(30) nelze použít, zřejmě zatím není v Node implementováno
      if (!res.ok) {
        console.error(`Download ${url}: unexpected response ${res.status}: ${res.statusText}`);
        return null;
      }
      await streamPipeline(res.body, fs.createWriteStream(file));
    } catch (error) {
      console.error(error);
      return null;
    } finally {
      clearTimeout(timeout);
    }
    console.log(
      `End download, result: ${res.status}: ${res.statusText} size: ${res.headers.get(
        'content-length',
      )}  type: ${res.headers.get('Content-Type')}`,
    );
    const fileInfo = {
      contentType: res.headers.get('Content-Type').toLowerCase(),
      bytes: parseInt(res.headers.get('Content-Length'), 10),
    };

    return new Promise((resolve, reject) => {
      resolve(fileInfo);
    });
  }

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.

*