„pobierz plik za pomocą node.js” - masz na myśli przesłanie na serwer? lub pobrać plik ze zdalnego serwera za pomocą swojego serwera? lub podać plik klientowi do pobrania z serwera node.js?
Joseph
66
„Chcę tylko pobrać plik z danego adresu URL, a następnie zapisać go w danym katalogu”, wydaje się to dość jasne. :)
Michelle Tilley,
34
Joseph niepoprawnie twierdzi, że wszystkie procesy węzłowe są procesami serwerowymi
lededje,
1
@lededje Co uniemożliwia procesowi serwera pobranie pliku i zapisanie go w katalogu na serwerze? Jest to doskonale wykonalne.
Gherman
Odpowiedzi:
598
Możesz utworzyć GETżądanie HTTP i potokować responseje do zapisywalnego strumienia plików:
Jeśli chcesz wesprzeć zbieranie informacji w wierszu poleceń - na przykład określenie pliku docelowego lub katalogu lub adresu URL - sprawdź coś takiego jak Commander .
Mam następujące wyjścia konsoli kiedy wpadłem ten skrypt: 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
Spróbuj użyć innego adresu URL w http.getwierszu; może http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg(i wymienić file.pngz file.jpg).
Michelle Tilley,
8
Czy ten kod poprawnie zamyka plik po zakończeniu skryptu, czy też utraci dane?
philk
2
@quantumpotato Spójrz na odpowiedź, którą otrzymujesz od swojej prośby
Michelle Tilley
6
Zależy to od typu adresu URL żądania https, jeśli chcesz , musisz użyć, w httpsprzeciwnym razie spowoduje to błąd.
Krishnadas PC
523
Nie zapomnij obsługiwać błędów! Poniższy kod oparty jest na odpowiedzi Augusto Romana.
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);});};
oddzwanianie mnie dezorientuje. jeśli teraz przywołam download(), jak mam to zrobić? Co chciałbym umieścić jako cbargument? Mam, download('someURI', '/some/destination', cb)ale nie rozumiem, co włożyć do cb
Abdul
1
@Abdul Oddzwanianie określasz za pomocą funkcji tylko wtedy, gdy musisz coś zrobić po pomyślnym pobraniu pliku.
CatalinBerta
65
Mówiąc o obsłudze błędów, jeszcze lepiej jest słuchać żądań błędów. Sprawdziłbym nawet, sprawdzając kod odpowiedzi. Tutaj uważa się za sukces tylko dla 200 kodów odpowiedzi, ale inne kody mogą być dobre.
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);});};
Pomimo względnej prostoty tego kodu, radziłbym użyć modułu żądania, ponieważ obsługuje on o wiele więcej protokołów (cześć HTTPS!), Które nie są natywnie obsługiwane http.
Można to zrobić tak:
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 yep, btw, istnieje również natywny moduł https , który może teraz obsługiwać bezpieczne połączenia.
Buzut
Bez wątpienia jest bardziej podatny na błędy. W każdym razie, w każdym przypadku, w którym użycie modułu żądania jest opcją, radzę, ponieważ jest to o wiele wyższy poziom, a zatem łatwiejsze i wydajniejsze.
Buzut
2
@Alex, nie, to komunikat o błędzie i zwrot. Więc jeśli response.statusCode !== 200cb on finishnigdy nie zostanie wywołany.
Buzut
1
Dziękujemy za pokazanie przykładu za pomocą modułu żądania.
Pete Alvin
48
Odpowiedź gfxmonk ma bardzo ścisły wyścig danych między wywołaniem zwrotnym a file.close()zakończeniem. file.close()faktycznie odbiera oddzwonienie, które jest wywoływane po zakończeniu zamykania. W przeciwnym razie natychmiastowe użycie pliku może się nie powieść (bardzo rzadko!).
Kompletne rozwiązanie to:
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.});});}
Bez oczekiwania na zakończenie, naiwne skrypty mogą kończyć się niekompletnym plikiem. Bez planowania cboddzwaniania przez zamknięcie możesz uzyskać wyścig między dostępem do pliku a plikiem, który jest w rzeczywistości gotowy.
Dwa komentarze na ten temat: 1) prawdopodobnie powinien odrzucić obiekty Error, a nie ciągi, 2) fs.unlink po cichu przełknie błędy, które niekoniecznie muszą być tym, co chcesz zrobić
Richard Nienaber
1
To działa świetnie! A jeśli adresy URL użyciu protokołu HTTPS, wystarczy podstawić const https = require("https");zaconst http = require("http");
Russ
15
Rozwiązanie z przekroczeniem limitu czasu, zapobieganie wyciekom pamięci:
Poniższy kod oparty jest na odpowiedzi Brandona Tilleya:
Możesz dodać limit czasu jak ja http.get. Przeciek pamięci występuje tylko wtedy, gdy pobieranie pliku trwa zbyt długo.
A-312
13
dla tych, którzy szukają sposobu opartego na obietnicy w stylu es6, myślę, że byłoby to coś w stylu:
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));
responseSetFlaga spowodowała, z jakiegoś powodu, dla którego nie miałem czasu na zbadanie, mój plik został pobrany niekompletnie. Nie wyskoczyły żadne błędy, ale plik .txt, który wypełniałem, zawierał połowę wierszy, które musiały tam być. Usunięto logikę flagi. Chciałem tylko podkreślić, że jeśli ktoś miałby problemy z tym podejściem. Mimo to +1
Milan Velebit
6
Kod Vince'a Yuan jest świetny, ale wydaje się, że coś jest nie tak.
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);});});}
Wygląda na to, że wniosek został wycofany 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."
Moduł http nie może https url, dostaniesz Protocol "https:" not supported.
Oto moja sugestia:
Wywołaj narzędzie systemowe, takie jak wgetlubcurl
użyj jakiegoś narzędzia, takiego jak węzeł-wget-obietnica, który również jest bardzo prosty w użyciu.
var wget = require('node-wget-promise');
wget('http://nodejs.org/images/logo.svg');
Oto jeszcze jeden sposób, aby sobie z tym poradzić bez zależności od strony trzeciej, a także poszukać przekierowań:
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')});
Zrzuty kodu są generalnie nieprzydatne i mogą zostać odrzucone lub usunięte. Warto byłoby edytować, aby przynajmniej wyjaśnić, co robi kod dla przyszłych użytkowników.
Odpowiedzi:
Możesz utworzyć
GET
żądanie HTTP i potokowaćresponse
je do zapisywalnego strumienia plików:Jeśli chcesz wesprzeć zbieranie informacji w wierszu poleceń - na przykład określenie pliku docelowego lub katalogu lub adresu URL - sprawdź coś takiego jak Commander .
źródło
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
wierszu; możehttp://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(i wymienićfile.png
zfile.jpg
).https
, jeśli chcesz , musisz użyć, whttps
przeciwnym razie spowoduje to błąd.Nie zapomnij obsługiwać błędów! Poniższy kod oparty jest na odpowiedzi Augusto Romana.
źródło
download()
sam jest wpipe
stanie?Jak powiedziała Michelle Tilley, ale z odpowiednim przepływem kontrolnym:
Bez oczekiwania na
finish
zdarzenie, naiwne skrypty mogą zakończyć się niepełnym plikiem.Edycja: Podziękowania dla @Augusto Roman za wskazanie, które
cb
należy przekazaćfile.close
, a nie wywołać jawnie.źródło
download()
, jak mam to zrobić? Co chciałbym umieścić jakocb
argument? Mam,download('someURI', '/some/destination', cb)
ale nie rozumiem, co włożyć do cbMówiąc o obsłudze błędów, jeszcze lepiej jest słuchać żądań błędów. Sprawdziłbym nawet, sprawdzając kod odpowiedzi. Tutaj uważa się za sukces tylko dla 200 kodów odpowiedzi, ale inne kody mogą być dobre.
Pomimo względnej prostoty tego kodu, radziłbym użyć modułu żądania, ponieważ obsługuje on o wiele więcej protokołów (cześć HTTPS!), Które nie są natywnie obsługiwane
http
.Można to zrobić tak:
źródło
response.statusCode !== 200
cb onfinish
nigdy nie zostanie wywołany.Odpowiedź gfxmonk ma bardzo ścisły wyścig danych między wywołaniem zwrotnym a
file.close()
zakończeniem.file.close()
faktycznie odbiera oddzwonienie, które jest wywoływane po zakończeniu zamykania. W przeciwnym razie natychmiastowe użycie pliku może się nie powieść (bardzo rzadko!).Kompletne rozwiązanie to:
Bez oczekiwania na zakończenie, naiwne skrypty mogą kończyć się niekompletnym plikiem. Bez planowania
cb
oddzwaniania przez zamknięcie możesz uzyskać wyścig między dostępem do pliku a plikiem, który jest w rzeczywistości gotowy.źródło
var request =
zostanie usunięta?Być może node.js się zmieniło, ale wydaje się, że istnieją pewne problemy z innymi rozwiązaniami (przy użyciu węzła v8.1.2):
file.close()
nafinish
wydarzenie. Domyślniefs.createWriteStream
jest ustawione na autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
powinien zostać wywołany w przypadku błędu. Może nie jest to potrzebne, gdy plik jest usuwany (unlink()
), ale zwykle jest to: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
bez oddzwaniania jest przestarzałe (ostrzeżenie o wyjściach)dest
plik istnieje; jest nadpisanePoniżej znajduje się zmodyfikowane rozwiązanie (wykorzystujące ES6 i obietnice), które rozwiązuje te problemy.
źródło
const https = require("https");
zaconst http = require("http");
Rozwiązanie z przekroczeniem limitu czasu, zapobieganie wyciekom pamięci:
Poniższy kod oparty jest na odpowiedzi Brandona Tilleya:
Nie twórz pliku, gdy pojawi się błąd, i korzystaj z limitu czasu, aby zamknąć żądanie po X sekundach.
źródło
http.get("http://example.com/yourfile.html",function(){})
http.get
. Przeciek pamięci występuje tylko wtedy, gdy pobieranie pliku trwa zbyt długo.dla tych, którzy szukają sposobu opartego na obietnicy w stylu es6, myślę, że byłoby to coś w stylu:
źródło
responseSet
Flaga spowodowała, z jakiegoś powodu, dla którego nie miałem czasu na zbadanie, mój plik został pobrany niekompletnie. Nie wyskoczyły żadne błędy, ale plik .txt, który wypełniałem, zawierał połowę wierszy, które musiały tam być. Usunięto logikę flagi. Chciałem tylko podkreślić, że jeśli ktoś miałby problemy z tym podejściem. Mimo to +1Kod Vince'a Yuan jest świetny, ale wydaje się, że coś jest nie tak.
źródło
Wolę request (), ponieważ możesz używać zarówno http, jak i https.
źródło
"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
źródło
Cześć, myślę, że możesz użyć modułu child_process i polecenia curl.
Ponadto, gdy chcesz pobrać duże 、 wiele plików, możesz użyć modułu klastra , aby użyć większej liczby rdzeni procesora.
źródło
Możesz użyć https://github.com/douzi8/ajax-request#download
źródło
ajax-request
nie jest to biblioteka strony trzeciej?Pobierz za pomocą obietnicy, która rozwiązuje czytelny strumień. umieść dodatkową logikę do obsługi przekierowania.
źródło
Jeśli używasz ekspresowego, użyj metody res.download (). w przeciwnym razie użyj modułu fs.
(lub)
źródło
Z mojej odpowiedzi do „Jaka jest różnica między .pipe a .pipeline w strumieniach” .
źródło
Ścieżka: img type: jpg random uniqid
źródło
Bez biblioteki wskazanie tego byłoby błędem. Tu jest kilka:
Protocol "https:" not supported.
Oto moja sugestia:
wget
lubcurl
var wget = require('node-wget-promise'); wget('http://nodejs.org/images/logo.svg');
źródło
źródło
Możesz spróbować użyć
res.redirect
adresu URL pobierania pliku https, a wtedy zostanie pobrany plik.Lubić:
res.redirect('https//static.file.com/file.txt');
źródło
źródło
Oto jeszcze jeden sposób, aby sobie z tym poradzić bez zależności od strony trzeciej, a także poszukać przekierowań:
źródło
download.js (tj. /project/utils/download.js)
app.js
źródło
Możemy użyć modułu węzła pobierania i jego bardzo prosty, patrz poniżej https://www.npmjs.com/package/download
źródło
źródło