Як завантажити файл з Node.js без використання сторонніх бібліотек ?
Мені нічого особливого не потрібно. Я хочу лише завантажити файл із заданої URL-адреси, а потім зберегти його у заданій теці.
Як завантажити файл з Node.js без використання сторонніх бібліотек ?
Мені нічого особливого не потрібно. Я хочу лише завантажити файл із заданої URL-адреси, а потім зберегти його у заданій теці.
Відповіді:
Ви можете створити HTTP- GET
запит і передати його response
в файл, що записується:
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);
});
Якщо ви хочете підтримати збір інформації в командному рядку - наприклад, вказати цільовий файл чи каталог або 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
його, інакше це призведе до помилки.
Не забудьте впоратися з помилками! Наступний код заснований на відповіді Августо Романа.
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()
сам pipe
здатний?
Як сказала Мішель Тіллі, але з відповідним контрольним потоком:
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);
});
});
}
Не чекаючи finish
події, наївні сценарії можуть закінчитися неповним файлом.
Редагувати: Дякую @Augusto Роман за те, що він вказав, що cb
слід передати file.close
, а не викликати прямо.
download()
, як би це зробити? Що б я поставив як cb
аргумент? Я маю, download('someURI', '/some/destination', cb)
але не розумію, що поставити на тесту
Якщо говорити про помилки обробки, то ще краще слухати помилки із запитом. Я б навіть підтвердив, перевіривши код відповіді. Тут він вважається успішним лише для 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 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);
});
};
Незважаючи на відносну простоту цього коду, я б радив використовувати модуль запиту, оскільки він обробляє багато інших протоколів (привіт 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);
});
};
response.statusCode !== 200
cb on finish
ніколи не буде викликаний.
Відповідь 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
зворотний виклик через закриття, ви можете отримати гонку між доступом до файлу та фактично готовим файлом.
var request =
її видалити?
Можливо, node.js змінився, але, схоже, є проблеми з іншими рішеннями (використовуючи node 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 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");
наconst http = require("http");
Наступний код заснований на відповіді Брендона Тіллі:
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();
});
});
Не створюйте файл, коли ви отримуєте помилку, і бажайте використовувати тайм-аут, щоб закрити ваш запит після X секунди.
http.get("http://example.com/yourfile.html",function(){})
http.get
. Витік пам'яті відбувається лише в тому випадку, якщо файл завантажується занадто багато часу.
для тих, хто прийшов у пошуках способу, що базується на обіцянках у стилі es6, я думаю, це було б щось на зразок:
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
прапор викликав, чому я не мав часу досліджувати, мій файл буде завантажений неповно. Жодних помилок не з’явилось, але файл .txt, який я заповнював, мав половину рядків, які там мали бути. Видалення логіки прапора виправлено. Просто хотілося вказати на те, чи є у когось проблеми з підходом. І все-таки +1
Код Вінса Юана великий, але, здається, щось не так.
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);
});
});
}
Я віддаю перевагу request (), оскільки ви можете використовувати як http, так і 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));
Привіт , Я думаю, ви можете використовувати модуль child_process і команду 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()
Крім того, коли ви хочете завантажити великі «декілька файлів», ви можете використовувати кластерний модуль, щоб використовувати більше ядер процесора.
Ви можете використовувати 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
це не стороння бібліотека?
Завантажте за допомогою обіцянок, які вирішують читабельний потік. введіть додаткову логіку для обробки переадресації.
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);
}
});
Якщо ви використовуєте метод експрес-використання res.download (). в іншому випадку використовується модуль fs.
app.get('/read-android', function(req, res) {
var file = "/home/sony/Documents/docs/Android.apk";
res.download(file)
});
(або)
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");
}
});
}
OТак, якщо ви використовуєте трубопровід , він закрив би всі інші потоки та переконався у відсутності витоків пам'яті.
Робочий приклад:
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.'); } ); });
З моєї відповіді на тему "Яка різниця між .pipe та .pipeline у потоках" .
Шлях: тип img: jpg випадковий 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;
}
Без бібліотеки можна було б просто відзначити. Ось декілька:
Protocol "https:" not supported.
Ось моя пропозиція:
wget
абоcurl
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');
});
Ось ще один спосіб вирішити цю проблему без сторонніх залежностей, а також пошуку переспрямувань:
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 (тобто /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')
});
Ми можемо використовувати модуль вузла для завантаження та його дуже простий, див. Нижче https://www.npmjs.com/package/download
var requestModule=require("request");
requestModule(filePath).pipe(fs.createWriteStream('abc.zip'));