Simple nodejs example with multiple files - node.js

I wrote very simple project on NodeJS. I want to make similarity to other language programming example, such as java. So I make: server.js, main.js and module (calc.js). Here are their code:
File server.js
var main = require('./main');
var http = require('http');
http.createServer(function(req, res){
main.main(req, res);
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
File main.js
var calc = require('./calc');
exports.main = function(req, res){
var a = 5;
var b = 9;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(calc.Plus(a,b));
res.end(calc.Minus(a,b));
};
File calc.js
(function(){
module.exports.Plus = function(a, b){
return a+b;
};
module.exports.Minus = function(a, b){
return a-b;
};
}());
I run it on my server, and I got an error:
Server running at http://127.0.0.1:8080/
_http_outgoing.js:558
throw new TypeError('First argument must be a string or Buffer');
^
TypeError: First argument must be a string or Buffer
at ServerResponse.OutgoingMessage.end (_http_outgoing.js:558:11)
at Object.exports.main (D:\workspace\FirstNodeJS\main.js:7:6)
at Server. (D:\workspace\FirstNodeJS\server.js:5:7)
at emitTwo (events.js:106:13)
at Server.emit (events.js:191:7)
at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:546:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:99:23)
I am just a newbie with NodeJS.

res.end() expects the first argument to be a string or a buffer. You are passing a number. That is how it is described in the doc here.
You could do:
res.end(calc.Plus(a,b).toString());
Also, you can only call res.end() once for a given response. If you want to send multiple things as part of the response, you can either combine them all into a string before using res.end() or you can call res.write() multiple times and then finish it with res.end().

There are 2 issues to your problem.
First problem is that the `.write(...) API from NodeJS's response object takes in a string buffer or string.
Quote:
response.write(chunk[, encoding][, callback])
chunk < string > | < Buffer >
encoding
callback Returns:
See: https://nodejs.org/api/http.html#http_response_write_chunk_encoding_callback
Your calculation methods Plus and Minus are returning Integer. Hence you need to convert the Numbers to String before writting;
Example:
var calc = require('./calc');
exports.main = function(req, res){
var a = 5;
var b = 9;
res.writeHead(200, {'Content-Type': 'text/plain'});
var result = calc.Plus(a,b);
res.write(result.toString());
res.write("\n");
result = calc.Minus(a,b);
res.write(result.toString());
res.end();
};
Also, problem number 2 is that you should only call .end(...) once for each response object.
You should either build your result and then call it. Or call .write(...) as many times as you need and when you are happy then close the communication by calling .end(...).
Another thing, you might want to line break \n your results so that the output looks like;
If not it will be a one liner, 14-4.

Related

Cannot read property 'toString' of undefined node.js filesystem

I have this script here, upon loading the page, it should first load a header html boilerplate, some dynamic paragraphs, and end the request with a footer html boiler plate. Both Boilerplates come from external files.
After testing, I am receiving:
TypeError: Cannot read property 'toString' of undefined
at ReadFileContext.callback (/user_code/index.js:20:23)
at FSReqWrap.readFileAfterOpen [as oncomplete] (fs.js:367:13)
My understanding was that I needed .toString() to ensure that what was loaded from the external files were buffered as strings.
exports.request = functions.https.onRequest((req, res) => {
fs.readFile('/public/templates/header-template.html', function(_err, data) {
res.write(data.toString());
console.log('Header Loaded');
});
res.writeHead(200, {'Content-Type': 'text/html'});
var q = url.parse(req.url, true).query;
var txt = '<p>Thanks <b>' + q.firstname + ' ' + q.lastname + '</b>. An email has been sent to <b>' + q.email + '</b> with details about your request.';
res.write(txt);
fs.readFile('/public/templates/footer-template.html', function(_err, data) {
res.end(data.toString());
console.log('Footer Loaded');
});
});
Any idea what I am doing wrong?
You should pass the encoding to toString() to convert from a Buffer.
data.toString('utf8');
Additionally, it seems your variable data is not defined, so perfhaps your file doesn't exists. Capture the error and see what's wrong:
if(_err){
console.error(_err);
}

How to pipe image from request to pdfkit in node.js?

First off, I am a total newbie both to Javascript and Node.js, so sorry if my question is stupid.
I am trying to scrape text and images off a website and export it to a pdf using request, cheerio and pdfkit, but I'm having problems.
I am able to scrape the images and save them locally using this:
var $ = cheerio.load(body);
$("#mediatab1 img").each(function(){
var image= 'http://WWW.WEBSITE.no' + $(this).attr('src');
images.push(image);
});
for(var i = 0; i < images.length; i++){
request(images[i]).pipe(fs.createWriteStream('images/' + i + '.jpg')); }
BUT! Here's the problem:
1. INTENT: When I try to write the files to the pdf using
doc.image('images/0.jpg');
all I get is
Error: Unknown image format.
at Function.PDFImage.open (C:\nodejs\node_modules\pdfkit\js\im
age.js:41:15)
at PDFDocument.module.exports.image (C:\nodejs\node_modules\pd
fkit\js\mixins\images.js:27:26)
at Request._callback (C:\nodejs\prosjekt.js:29:6)
at Request.self.callback (C:\nodejs\node_modules\request\reque
st.js:344:22)
at Request.emit (events.js:98:17)
at Request.<anonymous> (C:\nodejs\node_modules\request\request
.js:1239:14)
at Request.emit (events.js:117:20)
at IncomingMessage.<anonymous> (C:\nodejs\node_modules\request
\request.js:1187:12)
at IncomingMessage.emit (events.js:117:20)
at _stream_readable.js:944:16
0.jpg is 0 bytes, so I suspect there is a timing issue here?
2. INTENT
I tried to use .pipe instead of saving locally:
request(images[i]).pipe(doc.image(images[0]));
But all I get is:
"Error: ENOENT, no such file or directory 'C:\nodejs\http:\www.WEBSITE.no\Common\Tools\ImageScaler.ashx?id=c7d73548-8198-4bd1-867d-33fc0dfe73d1&h=4
13'
Any idea how to fix this or to solve the problem in any other way?
Here's the whole script:
var request = require('request'),
cheerio = require('cheerio'),
PDFDocument = require('pdfkit'),
doc = new PDFDocument,
fs = require('fs'),
prompt = require('prompt');
bilder = [];
prompt.start();
prompt.get(['prosjekturl'], function (err, result) {
request({url: 'http://www.WEBSITE.no/no/Prosjekter/Prosjekt/?pid=' + result.prosjekturl, encoding:null}, function(err, resp, body){
if(!err && resp.statusCode == 200){
// console.log(body);
var $ = cheerio.load(body);
$("#mediatab1 img").each(function(){
var bilde = 'http://www.WEBSITE.no' + $(this).attr('src');
bilder.push(bilde);
});
console.log(bilder);
for(var i = 0; i < bilder.length; i++){
request(bilder[i]).pipe(fs.createWriteStream('images/' + i + '.jpg'));
}
$("#MiddleRightContainer h1").each(function(){
var tittel = $(this).text();
console.log(tittel);
doc.pipe(fs.createWriteStream('pdf/output.pdf'));
doc.font('fonts/FONT-Regular.ttf');
doc.fontSize(32);
doc.text(tittel);
});
$("#MiddleRightContainer .user-content p").each(function(){
var tekst = $(this).text();
console.log(tekst);
doc.pipe(fs.createWriteStream('pdf/output.pdf'));
doc.fontSize(12);
doc.text(tekst);
});
$("#RightSidebar div.box2").each(function(){
var fakta = $(this).text();
console.log(fakta);
});
}
doc.end();
});
});
From docs:
"PDFKit supports the JPEG and PNG formats"
Here you can see it's checking .jpeg and .png extensions. Yours is a .jpg file. I've had trouble with this a few times and this has fixed my issue.
When it comes to the file loading I suspect that the windows paths can be a problem. Try and use node.js built-in path resolution: https://nodejs.org/api/path.html
When it comes to request and loading images it should not be more than:
request({
url: url,
// Prevents Request from converting response to string
encoding: null
}, function (err, response, body) {
doc.image(body)
})
Hope it helps some.

I want to pipe a readable css file to the http response

I have an issue with outputting the readable stream to the http response.
behind the scenes there is a regular request and response streams coming from the generic http createServer. I check to see if the 'req.url' ends in css, and I create a readable stream of this file. I see the css contents in the console.log, with the right css code I expect. Then, I try to pipe the readable css file stream to the response, but in Chrome, the file response is blank when I inspect the response. It is a 200 response though. Any thoughts at first glance? I've tried different variations of where I have code commented out.
router.addRoute("[a-aA-z0-9]{1,50}.css$", function(matches){
var cssFile = matches[0];
var pathToCss = process.cwd() + "/" + cssFile;
// takes care of os diffs regarding path delimiters and such
pathToCss = path.normalize(pathToCss);
console.log(matches);
console.log("PATH TO CSS");
console.log(pathToCss)
var readable = fs.createReadStream(pathToCss);
var write = function(chunk){
this.queue(chunk.toString());
console.log(chunk.toString());
}
var end = function(){
this.queue(null);
}
var thru = through(write,end);
//req.on("end",function(){
res.pipe(readable.pipe(thru)).pipe(res);
//res.end();
//});
});
you need to pipe your readable stream into your through-stream, and then pipe it into the response:
readable.pipe(thru).pipe(res);
edit: for preparing your css path, just use path.join instead of concatenating your path and normalizing it:
var pathToCss = path.join(process.cwd(), cssFile);
I separated out this route (css) from my normal html producing routes, the problem I had was that my normal routes in my router object returned strings, like res.end(compiled_html_str), and the css file readable stream was going through that same routing function. I made it separate by isolating it from my router.
var cssMatch = [];
if(cssMatch = req.url.match(/.+\/(.+\.css$)/)){
res.writeHead({"Content-Type":"text/css"});
var cssFile = cssMatch[1];
var pathToCss = process.cwd() + "/" + cssFile;
// takes care of os diffs regarding path delimiters and such
pathToCss = path.normalize(pathToCss);
console.log(cssMatch);
console.log("PATH TO CSS");
console.log(pathToCss)
var readable = fs.createReadStream(pathToCss);
var cssStr = "";
readable.on("data",function(chunk){
cssStr += chunk.toString();
});
readable.on("end",function(){
res.end(cssStr);
});
}

Node.js Beginner - Can't get past nodetuts tutorial number 2 - stdout and child process

I was trying to go through the tutorial nodetuts.com - tutorial 2 and unfortunatly could not get the example working, I'm very new to node.js and going through any tutorials I can get hold of. I understand that node.js is still beta and I figured that the code that makes this work is now obsolete. (This is the code):
var http = require('http');
var spawn = require('child_process').spawn;
http.createServer(function(request, response){
response.writeHead(200, {
'Content-Type' : 'text/plain'
});
var tail_child = spawn('tail', ['-f', 'test.txt']);
tail_child.stdout.on('data', function(data){
console.log(data.toString());
response.write(data);
});
}).listen(4000);
Anyway, determined to continue on I have been looking through the documentation on the node website and found this: http://nodejs.org/api/all.html#all_child_pid This is not exactly what I want (I want to complete that tutorial linked to up top) but I wanted to get something todo with child process working and incorperated that code into this:
var http = require('http');
var server = http.createServer(function(res, req){
res.writeHead(200);
res.end('testing');
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();
}).listen(4000);
Unfortunately when I refresh the page http://localhost:4000/ I get nothing and command prompt spits out: (I know it says writeHead is a problem, but it works fine in other examples - (like nodetuts - tutorial 1))
res.writeHead(200);
^
TypeError: Object #<IncomingMessage> has no method 'writeHead'
at Server.<anonymous> (Z:\Joseph Goss Folder\Google Drive\Code\javascript_first\nodejs_first\stdoutTest.js:20:6)
at Server.EventEmitter.emit (events.js:91:17)
at HTTPParser.parser.onIncoming (http.js:1785:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23)
at Socket.socket.ondata (http.js:1682:22)
at TCP.onread (net.js:404:27)
I wonder why I can't get this working, I'm obviously missing something but I don't know what, and I can't even get past tutorial number 2. :(
I'm running windows 7
I have also looked at this code Why does response.write appear to block my browser in Node.js? and his code doesn't work at all either.
You interchanged req and res in the function passed to createServer
var http = require('http');
var server = http.createServer(function(req, res){
res.writeHead(200);
res.end('testing');
var spawn = require('child_process').spawn,
grep = spawn('grep', ['ssh']);
console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();
}).listen(4000);

Making an HTTP request using node.js throws EAFNOSUPPORT

I'm trying to make a simple HTTP GET request using node.js, but I'm running into trouble using node.js v0.3.4-pre (i.e. compiled from HEAD as of this morning). Here's my code:
var cli = require('cli');
var http = require('http');
var url = require('url');
cli.parse();
cli.main(function(args, opts) {
this.debug(args[0]);
var siteUrl = url.parse(args[0]);
var site = http.createClient(siteUrl.port, siteUrl.host);
console.log(siteUrl);
var request = site.request("GET", siteUrl.pathname, {'host' : siteUrl.host})
request.end();
request.on('response', function(response) {
response.setEncoding('utf8');
console.log('STATUS: ' + response.statusCode);
response.on('data', function(chunk) {
console.log("DATA: " + chunk);
});
});
});
Here's the error that I get:
node.js:68
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: EAFNOSUPPORT, Address family not supported by protocol family
at doConnect (net.js:499:19)
at Client.connect (net.js:652:30)
at Client._ensureConnection (http.js:1033:10)
at Client.request (http.js:1048:8)
at Object.<anonymous> (/Users/paul/Desktop/readify.js:16:21)
at /usr/local/lib/node/.npm/cli/0.2.3-2/package/cli.js:995:18
at Object.main (/usr/local/lib/node/.npm/cli/0.2.3-2/package/cli.js:1000:9)
at Object.<anonymous> (/Users/paul/Desktop/readify.js:10:5)
at Module._compile (node.js:359:32)
at Object..js (node.js:367:14)
Found the bug, siteUrl.port will be undefined unless the URL explicitly names a port. So, the solution is:
var site = http.createClient(siteUrl.port || 80, siteUrl.host);
var site = http.createClient(siteUrl.port, siteUrl.host);
should rather be
var site = http.createClient(siteUrl.port || 80, siteUrl.hostname);
The same error message appeared on my very old XPSP2-box for ANY connect()-attempts. E.g npm wasn't able to do anything, and simple http requests failed.
While trying to find a solution, this post appeared all over the place, but its not the same issue.
In my case it had to do with WSAIoctl(...) always returning WSAEOPNOTSUPP when querying for WSAID_CONNECTEX, which seemed strange. This led me to a post recommending doing a "netsh winsock reset" from the cmd, which fixed the problem!

Resources