Làm cách nào để tôi tải xuống một tệp với Node.js mà không cần sử dụng thư viện của bên thứ ba ?
Tôi không cần bất cứ điều gì đặc biệt. Tôi chỉ muốn tải xuống một tệp từ một URL nhất định, sau đó lưu nó vào một thư mục nhất định.
Làm cách nào để tôi tải xuống một tệp với Node.js mà không cần sử dụng thư viện của bên thứ ba ?
Tôi không cần bất cứ điều gì đặc biệt. Tôi chỉ muốn tải xuống một tệp từ một URL nhất định, sau đó lưu nó vào một thư mục nhất định.
Câu trả lời:
Bạn có thể tạo một GET
yêu cầu HTTP và chuyển nó response
thành một luồng tệp có thể ghi:
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);
});
Nếu bạn muốn hỗ trợ thu thập thông tin trên dòng lệnh - như chỉ định tệp mục tiêu hoặc thư mục hoặc URL - hãy kiểm tra một cái gì đó như 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
dòng; có thể http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(và thay thế file.png
bằng file.jpg
).
https
bạn phải sử dụng https
nếu không nó sẽ gây ra lỗi.
Đừng quên xử lý lỗi! Các mã sau đây được dựa trên câu trả lời của 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);
});
};
download()
chính nó pipe
có thể?
Như Michelle Tilley đã nói, nhưng với dòng điều khiển thích hợp:
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);
});
});
}
Không chờ đợi finish
sự kiện, các kịch bản ngây thơ có thể kết thúc với một tệp không đầy đủ.
Chỉnh sửa: Cảm ơn @Augusto Roman đã chỉ ra rằng cb
nên được chuyển đến file.close
, không được gọi một cách rõ ràng.
download()
, tôi sẽ làm thế nào? Tôi sẽ đặt điều gì làm cb
đối số? Tôi có download('someURI', '/some/destination', cb)
nhưng không hiểu nên đặt gì vào cb
Nói về xử lý lỗi, nó thậm chí còn tốt hơn để nghe lỗi yêu cầu. Tôi thậm chí sẽ xác nhận bằng cách kiểm tra mã phản hồi. Ở đây, nó được coi là thành công chỉ với 200 mã phản hồi, nhưng các mã khác có thể tốt.
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);
});
};
Mặc dù sự đơn giản tương đối của mã này, tôi khuyên bạn nên sử dụng mô-đun yêu cầu vì nó xử lý nhiều giao thức hơn (xin chào HTTPS!) Mà không được hỗ trợ bởi http
.
Điều đó sẽ được thực hiện như vậy:
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 trên finish
sẽ không bao giờ được gọi.
Câu trả lời của gfxmonk có một cuộc đua dữ liệu rất chặt chẽ giữa cuộc gọi lại và việc file.close()
hoàn thành. file.close()
thực sự có một cuộc gọi lại được gọi khi đóng xong. Nếu không, việc sử dụng tập tin ngay lập tức có thể thất bại (rất hiếm khi!).
Một giải pháp hoàn chỉnh là:
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.
});
});
}
Không chờ đợi sự kiện kết thúc, các kịch bản ngây thơ có thể kết thúc với một tệp không đầy đủ. Nếu không lập lịch cb
gọi lại thông qua đóng, bạn có thể có một cuộc đua giữa việc truy cập tệp và tệp thực sự đã sẵn sàng.
var request =
bị xóa?
Có thể node.js đã thay đổi, nhưng có vẻ như có một số vấn đề với các giải pháp khác (sử dụng nút v8.1.2):
file.close()
trong finish
sự kiện. Mỗi mặc định, fs.createWriteStream
nó được đặt thành tự động Đóng: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
nên được gọi là lỗi. Có thể điều này không cần thiết khi tệp bị xóa ( unlink()
), nhưng thông thường nó là: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
không có cuộc gọi lại bị phản đối (cảnh báo đầu ra)dest
tập tin tồn tại; nó bị ghi đèDưới đây là một giải pháp sửa đổi (sử dụng ES6 và các lời hứa) xử lý các vấn đề này.
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");
choconst http = require("http");
Đoạn mã sau dựa trên câu trả lời của Brandon Tilley:
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();
});
});
Không tạo tệp khi bạn gặp lỗi và trước khi sử dụng thời gian chờ để đóng yêu cầu của bạn sau X giây.
http.get("http://example.com/yourfile.html",function(){})
http.get
. Việc rò rỉ bộ nhớ chỉ khi tập tin mất quá nhiều thời gian để tải xuống.
Đối với những người tìm kiếm theo cách hứa hẹn theo kiểu es6, tôi đoán nó sẽ giống như:
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
cờ gây ra, vì một số lý do mà tôi đã không có thời gian để điều tra, tệp của tôi sẽ được tải xuống không đầy đủ. Không có lỗi nào xuất hiện nhưng tệp .txt tôi đang điền có một nửa số hàng cần có ở đó. Loại bỏ logic cho cờ đã sửa nó. Chỉ muốn chỉ ra rằng nếu ai đó có vấn đề với cách tiếp cận. Tuy nhiên, +1
Mã của Vince Yuan rất tuyệt nhưng dường như có gì đó không đúng.
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);
});
});
}
Tôi thích request () vì bạn có thể sử dụng cả http và https với nó.
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));
Xin chào Tôi nghĩ rằng bạn có thể sử dụng mô đun child_ process và lệnh 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()
Ngoài ra, khi bạn muốn tải xuống nhiều tệp, bạn có thể sử dụng mô-đun cụm để sử dụng nhiều lõi cpu hơn.
Bạn có thể sử dụng https://github.com/douzi8/ajax-request#doad
request.download('http://res.m.ctrip.com/html5/Content/images/57.png',
function(err, res, body) {}
);
ajax-request
không phải là một thư viện bên thứ ba?
Tải xuống bằng lời hứa, giải quyết một luồng có thể đọc được. đặt thêm logic để xử lý chuyển hướng.
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);
}
});
Nếu bạn đang sử dụng phương thức express, hãy sử dụng phương thức res.doad (). mặt khác sử dụng mô đun fs.
app.get('/read-android', function(req, res) {
var file = "/home/sony/Documents/docs/Android.apk";
res.download(file)
});
(hoặc là)
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");
}
});
}
OVậy nếu bạn sử dụng đường ống , nó sẽ đóng tất cả các luồng khác và đảm bảo rằng không có rò rỉ bộ nhớ.
Ví dụ làm việc:
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.'); } ); });
Từ câu trả lời của tôi cho "Sự khác biệt giữa .pipe và .pipeline trên luồng" .
Đường dẫn: img loại: jpg ngẫu nhiên 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;
}
Không có thư viện, nó có thể bị lỗi chỉ để chỉ ra. Ở đây có một ít:
Protocol "https:" not supported.
Đây là gợi ý của tôi:
wget
hoặccurl
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');
});
Đây là một cách khác để xử lý nó mà không cần sự phụ thuộc của bên thứ 3 và cũng đang tìm kiếm các chuyển hướng:
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 (tức là /project/utils/doad.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')
});
Chúng tôi có thể sử dụng mô-đun nút tải xuống và rất đơn giản, vui lòng tham khảo bên dưới https://www.npmjs.com/package/doad
var requestModule=require("request");
requestModule(filePath).pipe(fs.createWriteStream('abc.zip'));