How to download a file with Node.js (without using third-party libraries)?
如何在不使用第三方库的情况下下载node.js文件?
我不需要什么特别的东西。我只想从给定的URL下载一个文件,然后将其保存到给定的目录中。
别忘了处理错误!以下代码基于奥古斯托·罗曼的答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); }); }; |
。
您可以创建一个HTTP
1 2 3 4 5 6 7 | 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的内容。
正如布兰登·蒂利所说,但有适当的控制流程:
1 2 3 4 5 6 7 8 9 10 11 12 | 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); }); }); } |
号
如果不等待
编辑:感谢@augusto roman指出,
说到处理错误,最好还是听听请求错误。我甚至会通过检查响应代码来验证。在这里,只有200个响应代码被认为是成功的,但是其他代码可能是好的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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); }); }; |
尽管这段代码相对简单,但我还是建议使用请求模块,因为它可以处理更多的协议(hello-https!)它不是由
应该这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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); }); }; |
。
gfxmonk的答案在回调和
完整的解决方案是:
1 2 3 4 5 6 7 8 9 10 11 12 | 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. }); }); } |
如果不等待finish事件,幼稚的脚本最终可能会得到一个不完整的文件。如果不通过close调度
可能node.js已经改变了,但其他解决方案(使用node v8.1.2)似乎有一些问题:
下面是一个改进的解决方案(使用ES6和Promises),用于处理这些问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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); } }); }); } |
号
对于那些寻求ES6风格的基于承诺的方式的人来说,我想应该是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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)); |
。
解决方案超时,防止内存泄漏:
以下代码基于Brandon Tilley的答案:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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秒后使用超时关闭请求。
袁文思的密码很好,但似乎有问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); }); }); } |
。
您可以使用https://github.com/douzi8/ajax请求下载
1 2 3 | request.download('http://res.m.ctrip.com/html5/Content/images/57.png', function(err, res, body) {} ); |
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)); |
号
如果您使用的是express,请使用res.download()方法。否则fs模块使用。
1 2 3 4 | app.get('/read-android', function(req, res) { var file ="/home/sony/Documents/docs/Android.apk"; res.download(file) }); |
号
(或)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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"); } }); } |
号
使用Promise下载,它可以解析可读的流。添加额外的逻辑来处理重定向。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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); } }); |
号
路径:img类型:JPG随机唯一性
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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; } |
嗨,我想您可以使用child_process module和curl命令。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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() |
号
另外,当您想要下载大的、多个文件时,可以使用集群模块来使用更多的CPU内核。
如果没有图书馆,只需指出一点就可以了。以下是一些:
- 无法处理HTTP重定向,如此URL https://calibre-ebook.com/dist/portable,它是二进制的。
- HTTP模块不能https url,你会得到
Protocol"https:" not supported. 。
我的建议是:
- 调用系统工具,如
wget 或curl 。 - 使用一些像node wget promise这样的工具也非常简单。埃多克斯1〔20〕
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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); }); }; |
号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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'); }); |
号
您可以尝试使用
比如:
1 2 3 | var requestModule=require("request"); requestModule(filePath).pipe(fs.createWriteStream('abc.zip')); |
号
我们可以使用下载节点模块,它非常简单,请参阅下面的网址:https://www.npmjs.com/package/download