"baixar um arquivo com node.js" - você quer dizer fazer upload para o servidor? ou recuperar um arquivo de um servidor remoto usando seu servidor? ou veicular um arquivo para um cliente para download no seu servidor node.js.
Joseph
66
"Eu só quero baixar um arquivo de um determinado URL e salvá-lo em um determinado diretório", parece bem claro. :)
Michelle Tilley
34
Joseph está fazendo uma afirmação incorreta de que todos os processos de nó são processos do servidor
lededje
1
@lededje O que impede um processo de servidor de baixar um arquivo e salvá-lo em um diretório em um servidor? É perfeitamente viável.
Gherman
Respostas:
598
Você pode criar uma GETsolicitação HTTP e canalizá-la responsepara um fluxo de arquivos gravável:
Se você deseja oferecer suporte à coleta de informações na linha de comando - como especificar um arquivo ou diretório de destino ou URL - consulte algo como o Commander .
Eu tenho a seguinte saída do console quando eu corri esse script: 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) .
Anderson Green
Tente usar um URL diferente na http.getlinha; talvez http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg(e substitua file.pngpor file.jpg).
precisa saber é o seguinte
8
Esse código fecha o arquivo corretamente quando o script termina ou ele perderia dados?
20915 philk
2
@quantumpotato Dê uma olhada na resposta que você está recebendo de volta do seu pedido
Michelle Tilley 8/18
6
Isso depende do tipo de URL de solicitação, se você estiver solicitando, httpsdeverá usar, httpscaso contrário, ocorrerá erro.
Krishnadas PC
523
Não se esqueça de lidar com erros! O código a seguir é baseado na resposta 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);});};
o retorno de chamada está me confundindo. se eu invocar agora download(), como faria? O que eu colocaria como cbargumento? Tenho a download('someURI', '/some/destination', cb), mas não entendo o que colocar no cb
Abdul
1
@Abdul Você especifica o retorno de chamada com uma função apenas se precisar fazer alguma coisa quando o arquivo tiver sido buscado com êxito.
CatalinBerta 17/05
65
Falando em lidar com erros, é ainda melhor ouvir solicitações de erros também. Eu até validaria verificando o código de resposta. Aqui é considerado sucesso apenas para 200 códigos de resposta, mas outros códigos podem ser bons.
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 successif(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);});};
Apesar da relativa simplicidade desse código, aconselho o uso do módulo request, pois ele lida com muitos outros protocolos (hello HTTPS!) Que não são suportados nativamente por http.
Isso seria feito assim:
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);});};
O módulo de solicitação funciona diretamente para HTTPs. Legal!
Thiago C. S Ventura
@ ventura sim, aliás, também há o módulo https nativo que agora pode lidar com conexões seguras.
Buzut
É mais propenso a erros, sem dúvida. De qualquer forma, em qualquer caso em que o uso do módulo de solicitação seja uma opção, eu o aconselharia, pois é muito mais alto e, portanto, mais fácil e eficiente.
Buzut
2
@ Alex, não, esta é uma mensagem de erro e há um retorno. Portanto, se response.statusCode !== 200o cb on finishnunca for chamado.
Buzut
1
Obrigado por mostrar o exemplo usando o módulo de solicitação.
Pete Alvin
48
A resposta de gfxmonk tem uma corrida de dados muito estreita entre o retorno de chamada e a file.close()conclusão. file.close()na verdade, recebe um retorno de chamada chamado quando o fechamento é concluído. Caso contrário, o uso imediato do arquivo poderá falhar (muito raramente!).
Uma solução completa é:
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.});});}
Sem aguardar o evento de conclusão, os scripts ingênuos podem acabar com um arquivo incompleto. Sem agendar o cbretorno de chamada por meio do fechamento, você pode ter uma corrida entre acessar o arquivo e o arquivo realmente estar pronto.
Dois comentários sobre isso: 1) ele provavelmente deveria rejeitar objetos Erro, não cordas, 2) fs.unlink vai erros tranquilamente andorinha que pode não ser necessariamente o que você quer fazer
Richard Nienaber
1
Isso funciona muito bem! E se os seus URLs usar HTTPS, basta substituir const https = require("https");porconst http = require("http");
Russ
15
Solução com tempo limite, evite vazamento de memória:
O código a seguir é baseado na resposta de Brandon Tilley:
este é apenas um arquivo, não tem nenhum protocolo ou servidor para transferência a partir ...http.get("http://example.com/yourfile.html",function(){})
Você pode adicionar tempo limite como eu fiz http.get. O vazamento de memória é apenas se o arquivo demorar muito para ser baixado.
A-312
13
para aqueles que vieram em busca da maneira baseada em promessas no estilo es6, acho que seria algo como:
var http = require('http');var fs = require('fs');function pDownload(url, dest){var file = fs.createWriteStream(dest);returnnewPromise((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));
responseSetA flag causou, por algum motivo que eu não tive tempo de investigar, meu arquivo para ser baixado incompletamente. Nenhum erro foi exibido, mas o arquivo .txt que eu estava preenchendo tinha metade das linhas que precisavam estar lá. A remoção da lógica do sinalizador a corrigiu. Só queria salientar se alguém tinha problemas com a abordagem. Ainda assim, +1
Milan Velebit 05/10
6
O código de Vince Yuan é ótimo, mas parece haver algo errado.
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);});});}
Parece que Request foi descontinuado github.com/request/request/issues/3142"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
módulo http não pode https url, você receberá Protocol "https:" not supported.
Aqui está minha sugestão:
Chame a ferramenta do sistema como wget oucurl
use alguma ferramenta como node-wget-promessa que também é muito simples de usar.
var wget = require('node-wget-promise');
wget('http://nodejs.org/images/logo.svg');
Aqui está outra maneira de lidar com isso sem dependência de terceiros e também procurando por redirecionamentos:
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.});});}
...// part of importsconst{ download }= require('./utils/download');...// add this function wherever
download('https://imageurl.com','imagename.jpg',()=>{
console.log('done')});
Geralmente, os despejos de código não são úteis e podem ser eliminados ou eliminados. Vale a pena editar para pelo menos explicar o que o código está fazendo para futuros visitantes.
Respostas:
Você pode criar uma
GET
solicitação HTTP e canalizá-laresponse
para um fluxo de arquivos gravável:Se você deseja oferecer suporte à coleta de informações na linha de comando - como especificar um arquivo ou diretório de destino ou URL - consulte algo como o Commander .
fonte
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
linha; talvezhttp://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(e substituafile.png
porfile.jpg
).https
deverá usar,https
caso contrário, ocorrerá erro.Não se esqueça de lidar com erros! O código a seguir é baseado na resposta de Augusto Roman.
fonte
download()
em sipipe
capaz?Como Michelle Tilley disse, mas com o fluxo de controle apropriado:
Sem aguardar o
finish
evento, scripts ingênuos podem acabar com um arquivo incompleto.Edit: Obrigado a @Augusto Roman por apontar que
cb
deve ser passado parafile.close
, e não chamado explicitamente.fonte
download()
, como faria? O que eu colocaria comocb
argumento? Tenho adownload('someURI', '/some/destination', cb)
, mas não entendo o que colocar no cbFalando em lidar com erros, é ainda melhor ouvir solicitações de erros também. Eu até validaria verificando o código de resposta. Aqui é considerado sucesso apenas para 200 códigos de resposta, mas outros códigos podem ser bons.
Apesar da relativa simplicidade desse código, aconselho o uso do módulo request, pois ele lida com muitos outros protocolos (hello HTTPS!) Que não são suportados nativamente por
http
.Isso seria feito assim:
fonte
response.statusCode !== 200
o cb onfinish
nunca for chamado.A resposta de gfxmonk tem uma corrida de dados muito estreita entre o retorno de chamada e a
file.close()
conclusão.file.close()
na verdade, recebe um retorno de chamada chamado quando o fechamento é concluído. Caso contrário, o uso imediato do arquivo poderá falhar (muito raramente!).Uma solução completa é:
Sem aguardar o evento de conclusão, os scripts ingênuos podem acabar com um arquivo incompleto. Sem agendar o
cb
retorno de chamada por meio do fechamento, você pode ter uma corrida entre acessar o arquivo e o arquivo realmente estar pronto.fonte
var request =
for removida?Talvez o node.js tenha mudado, mas parece que existem alguns problemas com as outras soluções (usando o nó v8.1.2):
file.close()
nofinish
evento. Por padrão,fs.createWriteStream
é definido como autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
deve ser chamado por erro. Talvez isso não seja necessário quando o arquivo for excluído (unlink()
), mas normalmente é: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
sem retorno de chamada é preterido (gera aviso)dest
arquivo existir; é substituídoAbaixo está uma solução modificada (usando ES6 e promessas) que lida com esses problemas.
fonte
const https = require("https");
porconst http = require("http");
Solução com tempo limite, evite vazamento de memória:
O código a seguir é baseado na resposta de Brandon Tilley:
Não crie arquivo quando ocorrer um erro e prefira usar o tempo limite para fechar sua solicitação após X segundos.
fonte
http.get("http://example.com/yourfile.html",function(){})
http.get
. O vazamento de memória é apenas se o arquivo demorar muito para ser baixado.para aqueles que vieram em busca da maneira baseada em promessas no estilo es6, acho que seria algo como:
fonte
responseSet
A flag causou, por algum motivo que eu não tive tempo de investigar, meu arquivo para ser baixado incompletamente. Nenhum erro foi exibido, mas o arquivo .txt que eu estava preenchendo tinha metade das linhas que precisavam estar lá. A remoção da lógica do sinalizador a corrigiu. Só queria salientar se alguém tinha problemas com a abordagem. Ainda assim, +1O código de Vince Yuan é ótimo, mas parece haver algo errado.
fonte
Prefiro request () porque você pode usar http e https com ele.
fonte
"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
fonte
Oi. Eu acho que você pode usar o módulo child_process e o comando curl.
Além disso, quando você deseja baixar grandes arquivos múltiplos, você pode usar o módulo de cluster para usar mais núcleos de CPU.
fonte
Você pode usar https://github.com/douzi8/ajax-request#download
fonte
ajax-request
não é uma biblioteca de terceiros?Faça o download usando a promessa, que resolve um fluxo legível. coloque lógica extra para lidar com o redirecionamento.
fonte
Se você estiver usando express use o método res.download (). caso contrário, use o módulo fs.
(ou)
fonte
Da minha resposta para "Qual é a diferença entre .pipe e .pipeline em fluxos" .
fonte
Caminho: img tipo: jpg uniqid aleatório
fonte
Sem biblioteca, poderia ser um buggy apenas para apontar. Aqui estão alguns:
Protocol "https:" not supported.
Aqui está minha sugestão:
wget
oucurl
var wget = require('node-wget-promise'); wget('http://nodejs.org/images/logo.svg');
fonte
fonte
Você pode tentar usar
res.redirect
o URL de download do arquivo https e, em seguida, ele fará o download do arquivo.Gostar:
res.redirect('https//static.file.com/file.txt');
fonte
fonte
Aqui está outra maneira de lidar com isso sem dependência de terceiros e também procurando por redirecionamentos:
fonte
download.js (por exemplo, /project/utils/download.js)
app.js
fonte
Podemos usar o módulo do nó de download e é muito simples, consulte abaixo https://www.npmjs.com/package/download
fonte
fonte