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ězd | Stáří | Velikost | Dep. | Sp. | |
---|---|---|---|---|---|
Axios | 95000 | 8 let | 446 kB | 2 | 4 |
Superagent | 16091 | 11 let | 531 kB | 11 | 8 |
Got | 11779 | 8 let | 249 kB | 13 | 2 |
Node-fetch | 7782 | 8 let | 107 kB | 3 | 5 |
Bent | 2165 | 5 let | 26,7 kB | 3 | 1 |
Needle | 1496 | 11 let | 259 kB | 3 | 1 |
Ky-universal | 544 | 3 roky | 6,85 kB | 2 | 1 |
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);
});
}