¿Cómo descargo un archivo con Node.js sin usar bibliotecas de terceros ?
No necesito nada especial Solo quiero descargar un archivo de una URL determinada y luego guardarlo en un directorio determinado.
¿Cómo descargo un archivo con Node.js sin usar bibliotecas de terceros ?
No necesito nada especial Solo quiero descargar un archivo de una URL determinada y luego guardarlo en un directorio determinado.
Respuestas:
Puede crear una GET
solicitud HTTP y canalizarla response
en una secuencia de archivo grabable:
const http = require('http');
const fs = require('fs');
const file = fs.createWriteStream("file.jpg");
const request = http.get("http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg", function(response) {
response.pipe(file);
});
Si desea admitir la recopilación de información en la línea de comandos, como especificar un archivo o directorio de destino o URL, consulte algo como Commander .
node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: connect ECONNREFUSED at errnoException (net.js:646:11) at Object.afterConnect [as oncomplete] (net.js:637:18)
.
http.get
línea; tal vez http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(y reemplazar file.png
con file.jpg
).
https
que deba usar, de lo https
contrario arrojará un error.
¡No olvides manejar los errores! El siguiente código se basa en la respuesta de Augusto Roman.
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
};
download()
propio pipe
poder?
Como dijo Michelle Tilley, pero con el flujo de control apropiado:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb);
});
});
}
Sin esperar el finish
evento, los guiones ingenuos pueden terminar con un archivo incompleto.
Editar: Gracias a @Augusto Roman por señalar que se cb
debe pasar a file.close
, no se llama explícitamente.
download()
, ¿cómo lo haría? ¿Qué pondría como cb
argumento? Tengo el download('someURI', '/some/destination', cb)
pero no entiendo qué poner en el CB
Hablando de errores de manejo, es aún mejor escuchar los errores de solicitud también. Incluso validaría comprobando el código de respuesta. Aquí se considera exitoso solo para el código de respuesta 200, pero otros códigos pueden ser buenos.
const fs = require('fs');
const http = require('http');
const download = (url, dest, cb) => {
const file = fs.createWriteStream(dest);
const request = http.get(url, (response) => {
// check if response is success
if (response.statusCode !== 200) {
return cb('Response status was ' + response.statusCode);
}
response.pipe(file);
});
// close() is async, call cb after close completes
file.on('finish', () => file.close(cb));
// check for request error too
request.on('error', (err) => {
fs.unlink(dest);
return cb(err.message);
});
file.on('error', (err) => { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
return cb(err.message);
});
};
A pesar de la relativa simplicidad de este código, recomendaría usar el módulo de solicitud, ya que maneja muchos más protocolos (¡Hola HTTPS!) Que no son compatibles de forma nativa http
.
Eso se haría así:
const fs = require('fs');
const request = require('request');
const download = (url, dest, cb) => {
const file = fs.createWriteStream(dest);
const sendReq = request.get(url);
// verify response code
sendReq.on('response', (response) => {
if (response.statusCode !== 200) {
return cb('Response status was ' + response.statusCode);
}
sendReq.pipe(file);
});
// close() is async, call cb after close completes
file.on('finish', () => file.close(cb));
// check for request errors
sendReq.on('error', (err) => {
fs.unlink(dest);
return cb(err.message);
});
file.on('error', (err) => { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
return cb(err.message);
});
};
response.statusCode !== 200
cb on finish
.
La respuesta de gfxmonk tiene una carrera de datos muy ajustada entre la devolución de llamada y la file.close()
finalización. file.close()
en realidad toma una devolución de llamada que se llama cuando se completa el cierre. De lo contrario, los usos inmediatos del archivo pueden fallar (¡muy raramente!).
Una solución completa es:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
});
}
Sin esperar el evento final, los guiones ingenuos pueden terminar con un archivo incompleto. Sin programar la cb
devolución de llamada a través del cierre, puede obtener una carrera entre acceder al archivo y el archivo que realmente está listo.
var request =
se elimina?
Quizás node.js ha cambiado, pero parece que hay algunos problemas con las otras soluciones (usando el nodo v8.1.2):
file.close()
en el finish
evento. Por defecto, el fs.createWriteStream
está configurado en autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
debe ser llamado por error. Quizás esto no sea necesario cuando se elimina el archivo ( unlink()
), pero normalmente es: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
sin una devolución de llamada está en desuso (advertencia de salida)dest
archivo existe; está anuladoA continuación se muestra una solución modificada (usando ES6 y promesas) que maneja estos problemas.
const http = require("http");
const fs = require("fs");
function download(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest, { flags: "wx" });
const request = http.get(url, response => {
if (response.statusCode === 200) {
response.pipe(file);
} else {
file.close();
fs.unlink(dest, () => {}); // Delete temp file
reject(`Server responded with ${response.statusCode}: ${response.statusMessage}`);
}
});
request.on("error", err => {
file.close();
fs.unlink(dest, () => {}); // Delete temp file
reject(err.message);
});
file.on("finish", () => {
resolve();
});
file.on("error", err => {
file.close();
if (err.code === "EEXIST") {
reject("File already exists");
} else {
fs.unlink(dest, () => {}); // Delete temp file
reject(err.message);
}
});
});
}
const https = require("https");
porconst http = require("http");
El siguiente código se basa en la respuesta de Brandon Tilley:
var http = require('http'),
fs = require('fs');
var request = http.get("http://example12345.com/yourfile.html", function(response) {
if (response.statusCode === 200) {
var file = fs.createWriteStream("copy.html");
response.pipe(file);
}
// Add timeout.
request.setTimeout(12000, function () {
request.abort();
});
});
No haga un archivo cuando reciba un error, y prefiera usar el tiempo de espera para cerrar su solicitud después de X segundos.
http.get("http://example.com/yourfile.html",function(){})
http.get
. La pérdida de memoria es solo si el archivo tarda demasiado en descargarse.
para aquellos que vinieron en busca de una forma basada en promesas de estilo es6, supongo que sería algo como:
var http = require('http');
var fs = require('fs');
function pDownload(url, dest){
var file = fs.createWriteStream(dest);
return new Promise((resolve, reject) => {
var responseSent = false; // flag to make sure that response is sent only once.
http.get(url, response => {
response.pipe(file);
file.on('finish', () =>{
file.close(() => {
if(responseSent) return;
responseSent = true;
resolve();
});
});
}).on('error', err => {
if(responseSent) return;
responseSent = true;
reject(err);
});
});
}
//example
pDownload(url, fileLocation)
.then( ()=> console.log('downloaded file no issues...'))
.catch( e => console.error('error while downloading', e));
responseSet
La bandera causó, por alguna razón que no había tenido tiempo de investigar, que mi archivo se descargara de forma incompleta. No aparecieron errores, pero el archivo .txt que estaba rellenando tenía la mitad de las filas que necesitaban estar allí. Eliminar la lógica de la bandera lo arregló. Solo quería señalar eso si alguien tenía problemas con el enfoque. Aún así, +1
El código de Vince Yuan es genial, pero parece estar mal.
function download(url, dest, callback) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function (response) {
response.pipe(file);
file.on('finish', function () {
file.close(callback); // close() is async, call callback after close completes.
});
file.on('error', function (err) {
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (callback)
callback(err.message);
});
});
}
Prefiero request () porque puedes usar http y https con él.
request('http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg')
.pipe(fs.createWriteStream('cat.jpg'))
"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
const download = (url, path) => new Promise((resolve, reject) => {
http.get(url, response => {
const statusCode = response.statusCode;
if (statusCode !== 200) {
return reject('Download error!');
}
const writeStream = fs.createWriteStream(path);
response.pipe(writeStream);
writeStream.on('error', () => reject('Error writing to file!'));
writeStream.on('finish', () => writeStream.close(resolve));
});}).catch(err => console.error(err));
Hola, creo que puedes usar el módulo child_process y el comando curl.
const cp = require('child_process');
let download = async function(uri, filename){
let command = `curl -o ${filename} '${uri}'`;
let result = cp.execSync(command);
};
async function test() {
await download('http://zhangwenning.top/20181221001417.png', './20181221001417.png')
}
test()
Además, cuando desee descargar grandes archivos múltiples, puede usar el módulo de clúster para usar más núcleos de CPU.
Puede usar https://github.com/douzi8/ajax-request#download
request.download('http://res.m.ctrip.com/html5/Content/images/57.png',
function(err, res, body) {}
);
ajax-request
no es una biblioteca de terceros?
Descargue usando promesa, que resuelve una secuencia legible. poner lógica extra para manejar la redirección.
var http = require('http');
var promise = require('bluebird');
var url = require('url');
var fs = require('fs');
var assert = require('assert');
function download(option) {
assert(option);
if (typeof option == 'string') {
option = url.parse(option);
}
return new promise(function(resolve, reject) {
var req = http.request(option, function(res) {
if (res.statusCode == 200) {
resolve(res);
} else {
if (res.statusCode === 301 && res.headers.location) {
resolve(download(res.headers.location));
} else {
reject(res.statusCode);
}
}
})
.on('error', function(e) {
reject(e);
})
.end();
});
}
download('http://localhost:8080/redirect')
.then(function(stream) {
try {
var writeStream = fs.createWriteStream('holyhigh.jpg');
stream.pipe(writeStream);
} catch(e) {
console.error(e);
}
});
Si está utilizando el método express use res.download (). de lo contrario, uso del módulo fs.
app.get('/read-android', function(req, res) {
var file = "/home/sony/Documents/docs/Android.apk";
res.download(file)
});
(o)
function readApp(req,res) {
var file = req.fileName,
filePath = "/home/sony/Documents/docs/";
fs.exists(filePath, function(exists){
if (exists) {
res.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Disposition" : "attachment; filename=" + file});
fs.createReadStream(filePath + file).pipe(res);
} else {
res.writeHead(400, {"Content-Type": "text/plain"});
res.end("ERROR File does NOT Exists.ipa");
}
});
}
✅Así que si usa tubería , cerraría todas las demás transmisiones y se aseguraría de que no haya pérdidas de memoria.
Ejemplo de trabajo:
const http = require('http'); const { pipeline } = require('stream'); const fs = require('fs'); const file = fs.createWriteStream('./file.jpg'); http.get('http://via.placeholder.com/150/92c952', response => { pipeline( response, file, err => { if (err) console.error('Pipeline failed.', err); else console.log('Pipeline succeeded.'); } ); });
De mi respuesta a "¿Cuál es la diferencia entre .pipe y .pipeline en streams" .
Ruta: tipo img: jpg random uniqid
function resim(url) {
var http = require("http");
var fs = require("fs");
var sayi = Math.floor(Math.random()*10000000000);
var uzanti = ".jpg";
var file = fs.createWriteStream("img/"+sayi+uzanti);
var request = http.get(url, function(response) {
response.pipe(file);
});
return sayi+uzanti;
}
Sin biblioteca, podría tener errores solo para señalar. Aquí hay algunos:
Protocol "https:" not supported.
Aquí mi sugerencia:
wget
ocurl
var wget = require('node-wget-promise');
wget('http://nodejs.org/images/logo.svg');
function download(url, dest, cb) {
var request = http.get(url, function (response) {
const settings = {
flags: 'w',
encoding: 'utf8',
fd: null,
mode: 0o666,
autoClose: true
};
// response.pipe(fs.createWriteStream(dest, settings));
var file = fs.createWriteStream(dest, settings);
response.pipe(file);
file.on('finish', function () {
let okMsg = {
text: `File downloaded successfully`
}
cb(okMsg);
file.end();
});
}).on('error', function (err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
let errorMsg = {
text: `Error in file downloadin: ${err.message}`
}
if (cb) cb(errorMsg);
});
};
var fs = require('fs'),
request = require('request');
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.cryptocompare.com/media/19684/doge.png', 'icons/taskks12.png', function(){
console.log('done');
});
Aquí hay otra forma de manejarlo sin dependencia de terceros y también buscando redireccionamientos:
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
https.get(url, function(response) {
if ([301,302].indexOf(response.statusCode) !== -1) {
body = [];
download(response.headers.location, dest, cb);
}
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
});
}
download.js (es decir, /project/utils/download.js)
const fs = require('fs');
const request = require('request');
const download = (uri, filename, callback) => {
request.head(uri, (err, res, body) => {
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
module.exports = { download };
app.js
...
// part of imports
const { download } = require('./utils/download');
...
// add this function wherever
download('https://imageurl.com', 'imagename.jpg', () => {
console.log('done')
});
Podemos usar el módulo de nodo de descarga y es muy simple, consulte a continuación https://www.npmjs.com/package/download
var requestModule=require("request");
requestModule(filePath).pipe(fs.createWriteStream('abc.zip'));