ฉันจะดาวน์โหลดไฟล์ด้วย Node.js โดยไม่ต้องใช้ห้องสมุดบุคคลที่สามได้อย่างไร
ฉันไม่ต้องการอะไรเป็นพิเศษ ฉันต้องการดาวน์โหลดไฟล์จาก URL ที่กำหนดและบันทึกลงในไดเรกทอรีที่กำหนด
ฉันจะดาวน์โหลดไฟล์ด้วย Node.js โดยไม่ต้องใช้ห้องสมุดบุคคลที่สามได้อย่างไร
ฉันไม่ต้องการอะไรเป็นพิเศษ ฉันต้องการดาวน์โหลดไฟล์จาก URL ที่กำหนดและบันทึกลงในไดเรกทอรีที่กำหนด
คำตอบ:
คุณสามารถสร้างGET
คำร้องขอHTTP และไพพ์คำขอ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 - ตรวจสอบบางอย่างเช่นผู้บัญชาการ
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
มิฉะนั้นจะทำให้เกิดข้อผิดพลาด
อย่าลืมจัดการข้อผิดพลาด! รหัสต่อไปนี้ขึ้นอยู่กับคำตอบของ 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()
เองpipe
ก็สามารถ?
ดังที่ Michelle Tilley กล่าว แต่ด้วยการควบคุมการไหลที่เหมาะสม:
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 Roman สำหรับการชี้ให้เห็นว่าcb
ควรส่งผ่านไปยังfile.close
ไม่ได้เรียกอย่างชัดเจน
download()
ฉันจะทำยังไงดี? ฉันจะวางอะไรเป็นcb
อาร์กิวเมนต์? ฉันมีdownload('someURI', '/some/destination', cb)
แต่ไม่เข้าใจสิ่งที่จะใส่ใน 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 บน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 มีการเปลี่ยนแปลง แต่ดูเหมือนว่ามีปัญหาบางอย่างกับการแก้ปัญหาอื่น ๆ (ใช้โหนด 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");
รหัสต่อไปนี้ขึ้นอยู่กับคำตอบของ 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();
});
});
อย่าสร้างไฟล์เมื่อคุณได้รับข้อผิดพลาดและใช้การหมดเวลาก่อนเพื่อปิดคำขอของคุณหลังจาก X secondes
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
รหัสของ Vince Yuan นั้นยอดเยี่ยม แต่ดูเหมือนจะผิดปกติ
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);
});
});
}
ฉันชอบคำขอ () เพราะคุณสามารถใช้ทั้ง 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");
}
});
}
✅ดังนั้นถ้าคุณใช้ไปป์ไลน์มันจะปิดสตรีมอื่น ๆ ทั้งหมดและตรวจสอบให้แน่ใจว่าไม่มีการรั่วไหลของหน่วยความจำ
ตัวอย่างการทำงาน:
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.'); } ); });
จากคำตอบของฉันถึง"ความแตกต่างระหว่าง. ท่อและ. ท่อบนสตรีม"คืออะไร
เส้นทาง: 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);
});
};
คุณสามารถลองใช้res.redirect
กับ URL การดาวน์โหลดไฟล์ https แล้วมันจะทำการดาวน์โหลดไฟล์
ชอบ: res.redirect('https//static.file.com/file.txt');
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'));