Writing a text file using request in nodejs - javascript

I've been trying to read a txt file from a URL and output my own text file using nodejs
Can anyone tell me what am I doing wrong in my code?
var fs = require('fs');
var request = require('request');
var stream = fs.createWriteStream("my_file.txt");
request('http://redsismica.uprm.edu/Data/prsn/EarlyWarning/Catalogue.txt', function (error, response, body) {
if (!error && response.statusCode == 200) {
firstLine = body.substring(0, body.indexOf('\n'));
console.log(firstLine);
stream.once('open', function(fd) {
wstream.write(firstLine, 'utf16le');//stream.write(firstLine);
stream.end();
});
}
})

Not sure what wstream is in your code but with request you can pipe your response directly to your write stream.
var stream = fs.createWriteStream('my_file.txt', { defaultEncoding: 'utf16le' });
stream.once('error', function(err) {
console.log(err);
});
stream.once('end', function() {
console.log('response written');
});
request('http://redsismica.uprm.edu/Data/prsn/EarlyWarning/Catalogue.txt')
.once('error', function(err) {
console.log('Request Error: ' + err);
})
.pipe(stream);

Related

Node request module with fs.createWriteStream() creates an empty file

I'm trying to upload an external url to my server. Here's what I got so far
var fs = require('fs');
var request = require('request');
var path = require('path');
const imagesFolder = 'downloadedAssets/imgs';
function download(url, dest, filename, cb) {
var file = fs.createWriteStream(dest + "/" + filename + path.extname(url));
request( {url: url}, function(err, response) {
if(err) {
console.log(err.message);
return;
}
response.pipe(file);
file.on('error', function(err) {
console.log(err.message);
file.end();
});
file.on('finish', function() {
file.close(cb);
});
});
}
and then executing the function...
var url = 'http://pngimg.com/uploads/spongebob/spongebob_PNG44.png';
download(url, imagesFolder, 'sponge', function onComplete(err) {
if (err) {
console.log(err.message);
} else {
console.log('image uploaded to server');
}
});
This doesn't throw any errors, and it creates a file name sponge.png, but the file is empty. Any idea why?
You might have mixed up the examples on the official website
Try using pipe() like below.
function download(url, dest, filename, cb) {
var file = fs.createWriteStream(dest + "/" + filename + path.extname(url));
request( {url: url}).pipe(file);
}

fs.createWriteStream on error event does not catch errors

I'm trying to upload images from a url to the server safely.
var http = require('http');
var fs = require('fs');
var path = require('path')
var download = function(url, dest, filename, cb) {
var file = fs.createWriteStream(dest + "/" + filename + path.extname(url));
var request = http.get(url, function(response) {
response.pipe(file);
file.on('error', function(err) {
console.log(err.message);
file.end();
});
file.on('finish', function() {
file.close(cb);
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest);
if (cb) cb(err.message);
});
}
var url = "https://vignette.wikia.nocookie.net/spongebob/images/d/d7/SpongeBob_stock_art.png";
download(url, 'downloadedAssets/imgs', 'spongebob', function onComplete(err) {
if (err) {
console.log(err.message);
} else {
console.log('image uploaded to server');
}
});
Which crashes the server
TypeError [ERR_INVALID_PROTOCOL]: Protocol "https:" not supported.
Expected "http:"
I understand I can't upload https files, but why does it crash the server instead of executing file.on('error') then ending the file.
I also tried try/catch and same thing
It crashes at http.get(url,function(){..}) because you are using http module. You need to use https module to do the get request to a https url.
const https = require('https');
https.get('https://encrypted.google.com/', (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
});
}).on('error', (e) => {
console.error(e);
});
You can use request module which support both http and https. From the doc:
Request is designed to be the simplest way possible to make http
calls. It supports HTTPS and follows redirects by default.const request = require('request');
const options = {
url: 'https://api.github.com/repos/request/request',
headers: {
'User-Agent': 'request'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
const info = JSON.parse(body);
console.log(info.stargazers_count + " Stars");
console.log(info.forks_count + " Forks");
}
}
request(options, callback);
Or to use Promises out of the box, use axios.
fs.createWriteStream is working absolutely fine so it is not throwing exceptions or errors.
The error is coming from http.get() method because you are trying to access 'https' using http module. Put debugger in http.get() module, you will definitely get error thrown.

Node.js error "terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"

I am using node.js on digital ocean and trying to run a file upload / download server.
To make sure the server runs in the background and does not quit on error, I am using the following
nohup nodejs server.js &
I am using nodejs instead of the node command because that is what digital ocean recommends.
This server is almost exlusively for uploading and downloading files. This works, for about two files, but then the server crashes with the following error:
"terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc"
I have no idea what is causing this, and I would appreciate any help. Preventing the crash would be great but also making it so the node server would not crash would also be great. I thought that is what nohup does, but apparently not. (I also haven't been able to get forever working correctly).
Here is the code for my server:
var http = require('http'),
url = require('url'),
util = require('util'),
path = require('path'),
fs = require('fs'),
qs = require('querystring');
var formidable = require('formidable'),
mime = require('mime');
var account = {username: 'test', password: 'etc'};
var accounts = [account],
port = 9090,
function dirTree(filename) {
var stats = fs.lstatSync(filename),
info = {
name: path.basename(filename),
path: ip + ':' + port + '/uploads/finished/' + path.basename(filename),
type: mime.lookup(filename).substring(0, 5)
};
if (stats.isDirectory()) {
info.type = "folder";
info.children = fs.readdirSync(filename).map(function(child) {
return dirTree(filename + '/' + child);
});
}
return info;
}
http.createServer(function(request, response) {
if(request.method.toLowerCase() == 'get') {
var filePath = './content' + request.url;
if (filePath == './content/') {
filePath = './content/home.html';
}
if (filePath == './content/feed') {
a = dirTree('./content/uploads/finished');
response.end(JSON.stringify(a));
}
var extname = path.extname(filePath);
var contentType = mime.lookup(extname);
fs.exists(filePath, function (exists) {
if (exists) {
fs.readFile(filePath, function (error, content) {
if (error) {
response.writeHead(500);
response.end();
}
else {
response.writeHead(200, {'Content-Type': contentType});
response.end(content, 'utf-8');
}
})
} else {
response.writeHead(404);
response.end();
}
});
}
if (request.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm;
if (request.url == '/verify') {
form.parse(request, function (err, fields, files) {
for (i = 0; i < accounts.length; i++) {
if (fields.username == accounts[i].username && fields.password == accounts[i].password) {
fs.readFile('./content/uploadForm.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
} else {
fs.readFile('./content/invalidLogin.html', function (error, content) {
if (error) {
response.end('There was an error');
} else {
response.end(content);
}
});
}
}
});
} else if (request.url == '/upload') {
var oldPath,
newPath,
fileName;
form.uploadDir = './content/uploads/temp/';
form.keepExtensions = true;
form.parse(request, function (err, fields, files) {
type = files['upload']['type'];
fileName = files['upload']['name'];
oldPath = files['upload']['path'];
newPath = './content/uploads/finished/' + fileName;
});
form.on('end', function () {
fs.rename(oldPath, newPath, function (err) {
if (err) {
response.end('There was an error with your request');
console.log('error')
} else {
response.end('<h1>Thanks for uploading ' + fileName + '<h1>');
}
});
});
}
}
}).listen(port);
console.log('listening on ' + port);
It looks like your script is just run out of the available memory.
Most likely you upload or download very large file and you read complete file in memory while receiving or sending.
You should rewrite you code using stream operations and process files chunk-by-chunk instead.

Saving image to node.js server without express.js

So I have been wondering how to save an image to node.js server without the use of express.(just learning node and want to make everything myself to learn node better, without express).
So far I have a form with the image as only input which I send with a post request. This is what I have so far on my server, which does not log anything.
if(req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function(e) {
console.log('Problem with request: ' + e.message);
});
res.writeHead(200, {'Content-Type': 'image/jpg; charset=utf8'});
req.on('data', function (chunk) {
fs.writeFile(__dirname + "/uploads/dada.jpg", chunk, function(err) {
if(err) {
console.log(err);
} else {
console.log("The file was saved!");
}
});
});
}
}
This is my form:
<form method="post" action="/upload" enctype="multipart/form-data">
EDIT: I fixed most of the problems, but the file is only saved as an image, but cannot be viewed like one. (Something is wrong with the content-type I guess, but don't know how to fix it)
Here is fiddle of my whole app. I know I need to separate it in different modules, but I will do that later
I completely forgot about this old question but now that I see it has quite some views, here is the solution I found:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs'),
GUID = require('GUID'),
formidable = require('formidable'),
util = require('util');
var app = http.createServer(function (req, res) {
if (req.method === 'POST') {
if (req.url === '/upload') {
req.on('error', function (e) {
console.log('Problem with request: ' + e.message);
});
var fileDirectory = __dirname + '/db/',
form = new formidable.IncomingForm();
form.keepExtensions = true;
form.uploadDir =fileDirectory;
form.parse(req, function (err, fields, files) {
if (err) throw (err);
var pic = JSON.stringify(util.inspect(files)),
upIndx = pic.indexOf('db'),
path = pic.slice(upIndx + 6, upIndx + 42);
res.writeHead(200, {
'Content-Type': 'text/html'
});
fs.readFile('views/index.html', function (err, page) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.write(page);
res.write('<div>Download Link: </div><div>' + fileDirectory + path + '</div>');
res.end();
});
});
}
} else {
//not important for question, handle other request
}
});
app.listen(port);
console.log('Server running on port: ' + port)

how to serve a file (exe or rar ) to a client for download from node.js server?

I have a a node.js server that serves an index.html with a text input for a password.
After a serverside password check the download should start for the client.
The client shouldn't be able to see the location path where the file lies on the server.
here is my server.js:
var
http = require('http'),
qs = require('querystring'),
fs = require('fs') ;
console.log('server started');
var host = process.env.VCAP_APP_HOST || "127.0.0.1";
var port = process.env.VCAP_APP_PORT || 1337;
http.createServer(function (req, res) {
if(req.method=='GET') {
console.log ( ' login request from ' + req.connection.remoteAddress );
fs.readFile(__dirname +'/index.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
} // method GET end
else{ // method POST start
console.log('POST request from ' + req.connection.remoteAddress);
var body = '';
req.on('data', function (data) {
body += data;
if (body.length > 500) {
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
req.connection.destroy(); console.log('too much data')}
});
req.on('end', function () {
var postdata = qs.parse(body);
var password = postdata.passwordpost ;
if (password == '7777777') {
console.log('the password is right, download starting');
// ??????????????????????????????????? here I need help from stackoverflow
}
else{
console.log ('password wrong');
fs.readFile(__dirname +'/wrongpassword.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
}
}); // req on end function end
}
}).listen(port, host);
the part where I need help is marked with ????????
here is my index.html:
<html>
<body>
<br> <br>
please enter your password to start your download
<br> <br>
<form method="post" action="http://localhost:1337">
<input type="text" name="passwordpost" size="50"><br><br>
<input type="submit" value="download" />
</form>
</body>
</html>
Do you know how to do this?
Sure, you can use this in your code :
res.setHeader('Content-disposition', 'attachment; filename='+filename);
//filename is the name which client will see. Don't put full path here.
res.setHeader('Content-type', 'application/x-msdownload'); //for exe file
res.setHeader('Content-type', 'application/x-rar-compressed'); //for rar file
var file = fs.createReadStream(filepath);
//replace filepath with path of file to send
file.pipe(res);
//send file
You needs to declare and require the path: path = require("path")
then can do:
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
path.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
}
check these complete example.
If you are willing to use express web framework, then it can be done in a much easier way.
app.get('/download', function(req, res){
var file = __dirname + 'learn_express.mp4';
res.download(file); // Sets disposition, content-type etc. and sends it
});
Express download API
I found some additional information about fs.createReadStream() ( especially error handling ) here and combined it with the answer of user568109. Here is my working downloadserver:
var
http = require('http'),
qs = require('querystring'),
fs = require('fs') ;
console.log('server started');
var host = process.env.VCAP_APP_HOST || "127.0.0.1";
var port = process.env.VCAP_APP_PORT || 1337;
http.createServer(function (req, res) {
if(req.method=='GET') {
console.log ( ' login request from ' + req.connection.remoteAddress );
fs.readFile(__dirname +'/index.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
} // method GET end
else{ // method POST start
console.log('POST request from ' + req.connection.remoteAddress);
var body = '';
req.on('data', function (data) {
body += data;
if (body.length > 500) {
// FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
req.connection.destroy(); console.log('too much data')}
});
req.on('end', function () {
var postdata = qs.parse(body);
var password = postdata.passwordpost ;
if (password == '7777777') {
console.log('the password is right, download starting');
res.setHeader('Content-disposition', 'attachment; filename='+'test1.exe');
//filename is the name which client will see. Don't put full path here.
res.setHeader('Content-type', 'application/x-msdownload'); //for exe file
res.setHeader('Content-type', 'application/x-rar-compressed'); //for rar file
var readStream = fs.createReadStream('/test1.exe');
//replace filepath with path of file to send
readStream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
readStream.pipe(res);
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
readStream.on('error', function(err) {
console.log (err) ;
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('an error occured', 'utf-8');
});
//send file
}
else{
console.log ('password wrong');
fs.readFile(__dirname +'/wrongpassword.html', function(error, content) {
if (error) {
res.writeHead(500);
res.end();
}
else {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
}
});
}
}); // req on end function end
}
}).listen(port, host);

Categories

Resources