"скачать файл с помощью node.js" - вы имеете в виду загрузку на сервер? или получить файл с удаленного сервера, используя ваш сервер? или передать файл клиенту для загрузки с вашего сервера node.js?
Иосиф
67
«Я только хочу скачать файл с заданного URL-адреса, а затем сохранить его в заданном каталоге», - кажется, это довольно ясно. :)
Мишель Тилли
34
Джозеф неверно утверждает, что все процессы узлов являются серверными процессами
lededje
1
@lededje Что мешает процессу сервера загрузить файл и сохранить его в каталоге на сервере? Это идеально выполнимо.
Герман
Ответы:
598
Вы можете создать HTTP- GETзапрос и направить его responseв поток файлов для записи:
Если вы хотите поддерживать сбор информации в командной строке - например, указание целевого файла или каталога или URL - проверьте что-то вроде 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) .
Андерсон Грин
Попробуйте использовать другой URL в http.getстроке; возможно http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg(и заменить file.pngна file.jpg).
Мишель Тилли
8
Закрывает ли этот код файл должным образом после завершения сценария или он потеряет данные?
Филк
2
@quantumpotato Посмотрите на ответ, который вы получаете от своего запроса
Мишель Тилли
6
Это зависит от типа req url, если вы запрашиваете, httpsвы должны использовать, httpsиначе это вызовет ошибку.
Кришнадас ПК
523
Не забывайте обрабатывать ошибки! Следующий код основан на ответе Аугусто Романа.
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(), как бы я это сделал? Что бы я привел в качестве cbаргумента? У меня есть, download('someURI', '/some/destination', cb)но я не понимаю, что положить в cb
Абдул
1
@Abdul Вы указываете обратный вызов с помощью функции, только если вам нужно что-то сделать, когда файл был успешно извлечен.
CatalinBerta
65
Говоря об обработке ошибок, еще лучше слушать ошибки запросов. Я бы даже подтвердил, проверив код ответа. Здесь это считается успешным только для кода ответа 200, но другие коды могут быть хорошими.
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);});};
Несмотря на относительную простоту этого кода, я бы посоветовал использовать модуль запроса, поскольку он обрабатывает гораздо больше протоколов (привет HTTPS!), Которые изначально не поддерживаютсяhttp .
Это будет сделано так:
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);});};
@ventura да, кстати, есть также нативный https модуль который теперь может обрабатывать защищенные соединения.
Бузут
Это больше подвержено ошибкам без сомнения. В любом случае, в любом случае, когда использование модуля запроса является опцией, я бы посоветовал его, поскольку он намного более высокого уровня и, следовательно, проще и эффективнее.
Бузут
2
@ Алекс, нет, это сообщение об ошибке и есть возврат. Так что если response.statusCode !== 200cb on finishникогда не будет вызван.
Бузут
1
Спасибо за показ примера с использованием модуля запроса.
Пит Элвин
48
Ответ gfxmonk имеет очень жесткую гонку данных между обратным вызовом и file.close()завершением. file.close()фактически принимает обратный вызов, который вызывается после завершения закрытия. В противном случае немедленное использование файла может завершиться неудачей (очень редко!).
Полное решение:
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.});});}
Не дожидаясь окончания события, наивные сценарии могут получить неполный файл. Не планируя cbобратный вызов через close, вы можете получить гонку между доступом к файлу и фактически готовым файлом.
Два комментария по этому поводу: 1) он, вероятно, должен отклонять объекты Error, а не строки, 2) fs.unlink будет тихо глотать ошибки, которые не обязательно должны быть тем, что вы хотите сделать
Ричард Нинабер
1
Это прекрасно работает! И если ваши URL - адреса с помощью HTTPS, просто заменить const https = require("https");наconst http = require("http");
Russ
15
Решение с таймаутом, предотвращение утечки памяти:
Вы можете добавить тайм-аут, как я сделал в http.get. Утечка памяти происходит только в том случае, если загрузка файла занимает слишком много времени.
A-312
13
для тех, кто искал способ, основанный на обещаниях в стиле es6, я думаю, это будет что-то вроде:
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));
responseSetПо какой-то причине, по причине которой у меня не было времени исследовать, флаг вызвал неполное скачивание моего файла. Никаких ошибок не появилось, но у файла .txt, который я заполнял, была половина строк, которые должны были быть там. Удаление логики для флага исправило это. Просто хотел указать на это, если у кого-то были проблемы с подходом. Тем не менее, +1
Милан Велебит
6
Код Винса Юаня хорош, но, похоже, что-то не так.
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);});});}
Похоже, запрос устарел 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."
Кроме того, если вы хотите загрузить большой файл с несколькими файлами, вы можете использовать кластерный модуль, чтобы использовать больше ядер процессора.
302 также является кодом статуса HTTP для перенаправления URL, поэтому вы должны использовать это [301,302] .indexOf (res.statusCode)! == -1 в операторе if
sidanmor
Вопросы были специфическими, чтобы не включать сторонние режимы :)
Дэвид Гатти
3
Если вы используете экспресс, используйте метод res.download (). в противном случае используйте модуль fs.
http модуль не может https URL, вы получите Protocol "https:" not supported.
Вот мое предложение:
Вызовите системный инструмент как wgetилиcurl
используйте некоторый инструмент, такой как node-wget-обещание, который также очень прост в использовании.
var wget = require('node-wget-promise');
wget('http://nodejs.org/images/logo.svg');
Вот еще один способ справиться с этим без сторонней зависимости, а также поиск перенаправлений:
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')});
Дампы кода, как правило, бесполезны и могут быть отклонены или удалены. Стоит отредактировать, чтобы хотя бы объяснить, что код делает для будущих посетителей.
Ответы:
Вы можете создать HTTP-
GET
запрос и направить егоresponse
в поток файлов для записи:Если вы хотите поддерживать сбор информации в командной строке - например, указание целевого файла или каталога или URL - проверьте что-то вроде 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
строке; возможноhttp://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(и заменитьfile.png
наfile.jpg
).https
вы должны использовать,https
иначе это вызовет ошибку.Не забывайте обрабатывать ошибки! Следующий код основан на ответе Аугусто Романа.
источник
download()
самpipe
умеет?Как сказала Мишель Тилли, но с соответствующим потоком управления:
Не дожидаясь
finish
события, наивные сценарии могут закончиться неполным файлом.Редактировать: Спасибо @Augusto Roman за указание, что
cb
должно быть переданоfile.close
, а не вызвано явно.источник
download()
, как бы я это сделал? Что бы я привел в качествеcb
аргумента? У меня есть,download('someURI', '/some/destination', cb)
но я не понимаю, что положить в cbГоворя об обработке ошибок, еще лучше слушать ошибки запросов. Я бы даже подтвердил, проверив код ответа. Здесь это считается успешным только для кода ответа 200, но другие коды могут быть хорошими.
Несмотря на относительную простоту этого кода, я бы посоветовал использовать модуль запроса, поскольку он обрабатывает гораздо больше протоколов (привет HTTPS!), Которые изначально не поддерживаются
http
.Это будет сделано так:
источник
response.statusCode !== 200
cb onfinish
никогда не будет вызван.Ответ gfxmonk имеет очень жесткую гонку данных между обратным вызовом и
file.close()
завершением.file.close()
фактически принимает обратный вызов, который вызывается после завершения закрытия. В противном случае немедленное использование файла может завершиться неудачей (очень редко!).Полное решение:
Не дожидаясь окончания события, наивные сценарии могут получить неполный файл. Не планируя
cb
обратный вызов через close, вы можете получить гонку между доступом к файлу и фактически готовым файлом.источник
var request =
удаляется?Возможно, файл node.js изменился, но, похоже, есть некоторые проблемы с другими решениями (с использованием узла v8.1.2):
file.close()
вfinish
случае. По умолчанию для этого параметраfs.createWriteStream
установлено значение autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
должен быть вызван по ошибке. Может быть, это не нужно, когда файл удален (unlink()
), но обычно это так: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
без обратного вызова не рекомендуется (выводит предупреждение)dest
файл существует; это отмененоНиже приведено модифицированное решение (с использованием ES6 и обещаний), которое решает эти проблемы.
источник
const https = require("https");
наconst http = require("http");
Решение с таймаутом, предотвращение утечки памяти:
Следующий код основан на ответе Брэндона Тилли:
Не создавайте файл, когда вы получаете ошибку, и предпочитайте использовать тайм-аут, чтобы закрыть ваш запрос после X секунд.
источник
http.get("http://example.com/yourfile.html",function(){})
http.get
. Утечка памяти происходит только в том случае, если загрузка файла занимает слишком много времени.для тех, кто искал способ, основанный на обещаниях в стиле es6, я думаю, это будет что-то вроде:
источник
responseSet
По какой-то причине, по причине которой у меня не было времени исследовать, флаг вызвал неполное скачивание моего файла. Никаких ошибок не появилось, но у файла .txt, который я заполнял, была половина строк, которые должны были быть там. Удаление логики для флага исправило это. Просто хотел указать на это, если у кого-то были проблемы с подходом. Тем не менее, +1Код Винса Юаня хорош, но, похоже, что-то не так.
источник
Я предпочитаю request (), потому что вы можете использовать как http, так и https.
источник
"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
источник
Привет, я думаю, что вы можете использовать модуль child_process и команду curl.
Кроме того, если вы хотите загрузить большой файл с несколькими файлами, вы можете использовать кластерный модуль, чтобы использовать больше ядер процессора.
источник
Вы можете использовать https://github.com/douzi8/ajax-request#download
источник
ajax-request
это не сторонняя библиотека?Загрузите, используя обещание, которое разрешает читаемый поток. поставить дополнительную логику для обработки перенаправления.
источник
Если вы используете экспресс, используйте метод res.download (). в противном случае используйте модуль fs.
(или)
источник
Из моего ответа на вопрос "В чем разница между .pipe и .pipeline в потоках" .
источник
Путь: img тип: jpg случайный уникальный
источник
Без библиотеки это может быть ошибкой, чтобы указать. Вот несколько из них:
Protocol "https:" not supported.
Вот мое предложение:
wget
илиcurl
var wget = require('node-wget-promise'); wget('http://nodejs.org/images/logo.svg');
источник
источник
Вы можете попробовать использовать
res.redirect
URL для загрузки файла https, и тогда он будет загружать файл.Подобно:
res.redirect('https//static.file.com/file.txt');
источник
источник
Вот еще один способ справиться с этим без сторонней зависимости, а также поиск перенаправлений:
источник
download.js (т.е. /project/utils/download.js)
app.js
источник
Мы можем использовать модуль загрузки узла и его очень просто, пожалуйста, обратитесь ниже https://www.npmjs.com/package/download
источник
источник