Jak mogę pobrać plik za pomocą Node.js bez korzystania z bibliotek stron trzecich ?
Nie potrzebuję niczego specjalnego. Chcę tylko pobrać plik z danego adresu URL, a następnie zapisać go w danym katalogu.
Jak mogę pobrać plik za pomocą Node.js bez korzystania z bibliotek stron trzecich ?
Nie potrzebuję niczego specjalnego. Chcę tylko pobrać plik z danego adresu URL, a następnie zapisać go w danym katalogu.
Odpowiedzi:
Możesz utworzyć GET
żądanie HTTP i potokować response
je do zapisywalnego strumienia plików:
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);
});
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 .
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że http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(i wymienić file.png
z file.jpg
).
https
, jeśli chcesz , musisz użyć, w https
przeciwnym razie spowoduje to błąd.
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);
});
};
download()
sam jest w pipe
stanie?
Jak powiedziała Michelle Tilley, ale z odpowiednim przepływem kontrolnym:
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);
});
});
}
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.
download()
, jak mam to zrobić? Co chciałbym umieścić jako cb
argument? Mam, download('someURI', '/some/destination', cb)
ale nie rozumiem, co włożyć do cb
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 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);
});
};
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);
});
};
response.statusCode !== 200
cb on finish
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:
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 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.
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()
na finish
wydarzenie. Domyślnie fs.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.
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");
zaconst http = require("http");
Poniższy kod oparty jest na odpowiedzi Brandona Tilleya:
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();
});
});
Nie twórz pliku, gdy pojawi się błąd, i korzystaj z limitu czasu, aby zamknąć żądanie po X sekundach.
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:
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
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 +1
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);
});
});
}
Wolę request (), ponieważ możesz używać zarówno http, jak i https.
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));
Cześć, myślę, że możesz użyć modułu child_process i polecenia 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()
Ponadto, gdy chcesz pobrać duże 、 wiele plików, możesz użyć modułu klastra , aby użyć większej liczby rdzeni procesora.
Możesz użyć 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
nie jest to biblioteka strony trzeciej?
Pobierz za pomocą obietnicy, która rozwiązuje czytelny strumień. umieść dodatkową logikę do obsługi przekierowania.
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);
}
});
Jeśli używasz ekspresowego, użyj metody res.download (). w przeciwnym razie użyj modułu fs.
app.get('/read-android', function(req, res) {
var file = "/home/sony/Documents/docs/Android.apk";
res.download(file)
});
(lub)
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");
}
});
}
✅ Więc jeśli użyjesz potoku , zamknie on wszystkie inne strumienie i upewni się, że nie ma wycieków pamięci.
Przykład roboczy:
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.'); } ); });
Z mojej odpowiedzi do „Jaka jest różnica między .pipe a .pipeline w strumieniach” .
Ścieżka: img type: 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;
}
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');
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');
});
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.
});
});
}
download.js (tj. /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')
});
Możemy użyć modułu węzła pobierania i jego bardzo prosty, patrz poniżej https://www.npmjs.com/package/download
var requestModule=require("request");
requestModule(filePath).pipe(fs.createWriteStream('abc.zip'));