Currently have the following Node.js architecture: index.js + server.js + router.js + requestHandlers.js
HTML is currently embedded in requestHandlers.js, effectively making Node.js the View & Controller.
What is an easy way for the HTML be externalized?
requestHandlers.js:
var querystring = require("querystring"),
fs = require("fs");
function start(response, postData) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent the text: "+
querystring.parse(postData).text);
response.end();
}
exports.start = start;
exports.upload = upload;
exports.show = show;
I'd reccommend you not to re-invent the wheel and use some framework, like express.
But if you want to do it your way, then you should use some templating engine, like dust / mustache /jade and put all your html into separate template files.
Then, when you handle your request, you use file input/output , to read those files, pass them through template engine, and send the result to client.
you could do something like this
fs = require('fs')
fs.readFile('./views/index.html', 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
//data now contains the content of index.html, do what you want with it
});
Related
So I just made a HTML page added a script tag with src to a js file and sent the HTML file as response with node js using HTTP module.
But the js file is not working and when I checked the network tab I saw js file is received as text/html file.
Following are the js and html codes.
Server code with node js
const http = require('http') ;
const file = require('fs') ;
const server = http.createServer((req, res) => {
file.readFile('public/login.html', (err, data) => {
if (err) throw err ;
res.writeHead(200, {'Content-Type': 'text/html'}) ;
res.write(data) ;
res.end() ;
})
}) ;
server.listen(5000) ;
front end code : login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<script defer src="js/index.js"></script>
</head>
<body>
<h1>Login</h1>
<form action="" method="post">
<input type="email" name="user" id="user">
<input type="password" name="pass" id="pass">
<button type="submit" name="button" value="login">Login</button>
</form>
</body>
</html>
now when I load the page at localhost:5000, js does not execute and it's received as text/html.
The browser will receive the HTML, see the script tag, and request js/index.js from your server. But your server only sends your HTML file. It doesn't pay any attention to what the browser requested, it just always sends back the HTML. So the script is never sent to the browser, so the browser can't execute it.
Your server code needs to look at req to determine what was requested (looking at url, etc.), and send an appropriate response, rather than always sending back the same content.
Here's a fairly simple example that handles /, /login.html, and /js/index.js paths (making the first two synonyms):
const http = require('http');
const file = require('fs');
const FILENAME_404 = "public/404.html";
const server = http.createServer((req, res) => {
let filename = null;
let contentType = "text/html";
let status = 200;
// What did the browser ask for?
switch (req.url.toLowerCase()) {
case "/":
case "/login.html":
// The login page
filename = "public/login.html";
break;
case "/js/index.js":
// The JavaScript file
filename = "public/js/index.js";
contentType = "text/javascript";
break;
default:
// Something we don't support -- send a 404
filename = FILENAME_404;
status = 404;
break;
}
sendFile(res, filename, contentType, status);
});
function sendFile(res, filename, contentType, status, callback) {
file.readFile(filename, (err, data) => {
if (err) {
// Couldn't read the file, send a 404
if (filename !== FILENAME_404) {
sendFile(res, FILENAME_404, "text/html", 404);
} else {
// Couldn't even find the 404 file, send a minimal plaintext 404
res.writeHead(404, {"Content-Type": "text/plain"});
res.write("The requested resource does not exist on this server.");
res.end();
}
} else {
res.writeHead(status, {"Content-Type": contentType});
res.write(data);
res.end();
}
});
}
server.listen(5000);
Note: This is just an example. If you're going to build anything of any size, you'll want more structure than this. You might look at Express or Koa or others that handle more of the HTTP plumbing, URL routing, etc. for you and have modules available for other things as well.
My code shows a simple upload form (node-formidable and node.js). I am using socket.io to update the client on it's current upload file progress. My problem is that I currently emit the progress update to every clients. As an example, if I start an upload with clientA, then connect to the website with clientB, clientB will see the exact same progress bar as clientA. Normally, clientA and clientB should be different, with their own respective progress bars, linked only with their respective uploads.
This is my app.js file
// Required modules
var formidable = require('formidable'),
http = require('http'),
util = require('util'),
fs = require('fs-extra');
// Path to save file, server side
var savePath = "./uploadedFiles/";
// Loading index.html
var server = http.createServer(function(req, res) {
// Form uploading Process code
//Upload route
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// creates a new incoming form.
var form = new formidable.IncomingForm();
// set the path to save the uploaded file on server
form.uploadDir = savePath;
// updating the progress of the upload
form.on('progress', function(bytesReceived, bytesExpected) {
io.sockets.in('sessionId').emit('uploadProgress', (bytesReceived * 100) / bytesExpected);
});
// parse a file upload
form.parse(req, function (err, fields, files) {
res.writeHead(200, { 'content-type': 'text/plain' });
res.write('Upload received :\n');
res.end(util.inspect({ fields: fields, files: files }));
});
form.on('end', function (fields, files) {
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name;
/* Files are nammed correctly */
fs.rename(temp_path, savePath + file_name, function(err) {
if ( err ) console.log('ERROR: ' + err);
});
});
return;
}
fs.readFile('./index.html', 'utf-8', function(error, content) {
res.writeHead(200, {"Content-Type": "text/html"});
res.end(content);
});
});
// socket.io
var io = require('socket.io').listen(server);
io.on('connection', function (socket) {
socket.join("sessionId");
});
server.listen(8080);
This is my index.html file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Socket.io</title>
</head>
<body>
<h1>Test d'upload</h1>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8080');
socket.on('uploadProgress' , function (progress){
document.getElementById("currentProgress").value = progress;
});
</script>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="upload" multiple="multiple"><br>
<input type="submit" value="Upload">
</form>
<p><progress id="currentProgress" value="0" max="100"></progress></p>
</body>
</html>
I do not have more code than this. I am new to node.js and socket.io, so I am not sure about the interactions between them and between the client and server.
How can I change my code to update only the right client?
Thank you anyway for your time.
a suggestion
there is a basic way
socketIO.sockets.socket(this.socketid).emit(<event>, dataObj);
if your function is inside your socket code...otherwise I will often do something like this
connection.query("select socketid from websocket_sessions where user_id=" + data.form.user_id, function(err, users) {
socketIO.sockets.socket(users[0].socketid).emit(<event>, dataObj);
});
where I am always updating or a
i want to execute the javascript file in the header of an dynamically created html page with a node.js webserver. can't figure out how but must be possible.
var http = require('http');
var url = require('url');
function processRequest(request, response) {
"use strict";
var pathname = url.parse(request.url).pathname;
console.log('Requested ' + pathname);
response.writeHead(1000, { 'Content-Type': 'text/html' });
response.write('<!DOCTYPE html><html ><head>');
response.write('<meta charset="utf-8">');
response.write('<title>' + 'Yay Node!' + '</title>');
response.write('<link rel=stylesheet href=../styles/styles.css rel=stylesheet />');
response.write('<script src=script.js type=text/javascript></script>');
response.write('</head><body>');
response.write('<h1><tt>' + 'jan' + '</tt></h1>');
response.write('<script type="text/javascript">test()</script>')
//response.write('<script type="text/javascript">script.onload = function () { alert("from html Node!")}; </script>')
response.write('<input id="clickMe" type="button" value="clickme" onclick="test()" />')
response.write('</body></html>');
response.end();
};
http.createServer(processRequest).listen(8888);
script.js:
document.onload = function () { alert('load Node!'); };
test = function() { alert('test Node!') };
the problem is, that your browser can't find script.js
When it tries to get http://localhost:8888/script.js node answers with an html file that is the same as http://localhost:8888/.
In order for node to correctly serve the script file, you need to check the path and send the correct file.
add something like this to your processRequest function
if (pathname === '/script.js') {
//code to send script
} else {
//code to send html
}
you would have to do the same for the styles.css file as well
if you don't want to hardcode every file in your page, I would recommend using the npm module express
var express = require('express'),
app = express(),
server = require('http').createServer(app);
app.use('/', express.static(__dirname + '/static');
server.listen(8888);
this code will automatically send the files in /static when the browser requests them.
if you want to create a dynamic page, you can add this between the app.use and the server.listen
app.all('/somedynamicurl', function (request, response) {
//Dynamic page
});
now, if someone goes to http://localhost:8888/somedynamicurl they'll get this dynamic page.
I'd also recommend reading the express guide and the express docs
this works. thanks to Ferdi265.
// http://www.cburch.com/cs/340/reading/nodejs/
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
var mimeTypes = {
'.js': 'text/javascript',
'.html': 'text/html',
'.css': 'text/css'
};
function processRequest(request, response) {
"use strict";
var pathname = url.parse(request.url).pathname;
console.log('Requested ' + pathname);
var lookup = path.basename(decodeURI(request.url)), //|| 'index.html',
f = lookup;
fs.exists(f, function (exists) {
if (exists) {
fs.readFile(f, function (err, data) {
if (err) {
response.writeHead(500);
response.end('Server Error!'); return;
}
var headers = {
'Content-type': mimeTypes[path.
extname(lookup)]
};
response.writeHead(200, headers);
response.end(data);
});
// return;
}
else {
response.writeHead(1000, { 'Content-Type': 'text/html' });
response.write('<!DOCTYPE html><html ><head>');
response.write('<meta charset="utf-8">');
response.write('<title>' + 'Yay Node!' + '</title>');
response.write('<link rel=stylesheet href=../styles/styles.css rel=stylesheet />');
response.write('<script src=script.js type=text/javascript></script>');
response.write('</head><body>');
response.write('<h1><tt>' + 'jan' + '</tt></h1>');
response.write('<script type="text/javascript">test()</script>')
//response.write('<script type="text/javascript">script.onload = function () {
alert("from html Node!")}; </script>')
response.write('<input id="clickMe" type="button" value="clickme"
onclick="test()" />')
response.write('</body></html>');
response.end();
}
});
};
http.createServer(processRequest).listen(8888);
I've read this link Node.js - external JS and CSS files (just using node.js not express) and comprehended somewhat but still do not know where to plug them in, in my case. Consider a 'Hello World' node.js app bellow, 2 lines, link and script, in the head section would not work. I guess because they are not web-reference yet. So, how do I include them in? If I do like the link suggests, would they be outside of the head section?
var http = require('http');
var html =
'<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'+
'<link rel="stylesheet" type="text/css" href="./mystyle.css">'+
'<script src="./myscript.js"></script>'+
'</head>'+
'<body>'+
'<p>Hello World!</p>'+
'</body>'+
'</html>';
http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(html);
response.end();
}).listen(80);
You should be using response.writeHead, not request.writeHead.
Also, the current code will return the same file regardless of the js or css request.
Basically, you need the server to deliver your public files. Now the easiest way to do this would be to use express, and set up the static middleware.
However, if you really don't want to use express, I still think the easiest way to do this would be to use the connect static middleware.
Something along the lines of :
var http = require('http');
var static = require('static')('/');
http.createServer(static).listen(80);
This would create a basic web server delivering the files in your / directory.
I got it, finally! Like I said it would help me to understand the basic structure and interaction between node.js and browser. Thank you everyone. Here is the code.
var http = require('http');
var fs = require('fs');
var i = 0;
var html =
'<html>'+
'<head>'+
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'+
'<link rel="stylesheet" type="text/css" href="./mystyle.css">'+
'<script src="./myscript.js"></script>'+
'</head>'+
'<body>'+
'<p>Hello World!</p>'+
'</body>'+
'</html>';
http.createServer(function(request, response) {
i++;
console.log('Request #'+i+': '+request.url);
if (request.url.indexOf('.js') != -1) {
fs.readFile(__dirname + '/misc/myscript.js', function (err, data) {
if (err) console.log(err);
else {
console.log('/misc/myscript.js: fs.readFile is successful');
response.setHeader("Content-Length", data.length);
response.setHeader("Content-Type", 'text/javascript');
response.statusCode = 200;
response.end(data);
}
});
}
else if (request.url.indexOf('.css') != -1) {
fs.readFile(__dirname + '/misc/mystyle.css', function (err, data) {
if (err) console.log(err);
else {
console.log('/misc/mystyle.css: fs.readFile is successful');
response.setHeader("Content-Length", data.length);
response.setHeader("Content-Type", 'text/css');
response.statusCode = 200;
response.end(data);
}
});
}
else {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(html);
response.end();
}
}).listen(80);
I just started working with node.js and json objects in my college course. One of our assignments this week was to create a few json objects and extract parts of the object into an html page. I thought I had a good grasp on how to do this, but I am running into an error when I try to start node. If I remove the colleges object and the parse statement then node runs fine.
Here is the error I get when I run "node index.js":
undefined:1
[object Object],[object Object],[object Object],[object Object],[object Object
^
SyntaxError: Unexpected token o
at Object.parse (native)
at Object.<anonymous> (/home/ubuntu/node_stuff/node_json/requestHandlers.js:13:20)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.require (module.js:362:17)
at require (module.js:378:17)
at Object.<anonymous> (/home/ubuntu/node_stuff/node_json/index.js:3:23)
at Module._compile (module.js:449:26)
And here is the code I am working with.
var querystring = require("querystring"),
fs = require("fs"),
formidable = require("formidable");
var colleges = [
{"name":"A-B Tech","street":"340 Victoria Road","city":"Asheville","state":"NC","zip":"28801","phone":"828-254-1921"},
{"name":"UNC Asheville","street":"1 University Heights","city":"Asheville","state":"NC","zip":"28804","phone":"828-251-6600"},
{"name":"UNC Charlotte","street":"9201 University City Blvd","city":"Charlotte","state":"NC","zip":"28223","phone":"704-687-8622"},
{"name":"Western Carolina","street":"North Carolina 107","city":"Cullowhee","state":"NC","zip":"28723","phone":"877-928-4968"},
{"name":"NC State","street":"2200 Hillsborough","city":"Raleigh","state":"NC","zip":"27695","phone":"919-515-2011"}
];
var college = JSON.parse(colleges);
function abtech(response) {
console.log("Request handler 'abtech' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<ul>'+
'<li>' + college[0].name + '</li>'+
'<li>' + college[0].street + '</li>'+
'<li>' + college[0].city + ' ' + college[0].state + ' ' + college[0].zip + '</li>'+
'<li>' + college[0].phone + '</li>'+
'</ul>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function unca(response) {
console.log("Request handler 'abtech' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<ul>'+
'<li></li>'+
'<li></li>'+
'<li></li>'+
'<li></li>'+
'</ul>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function home(response) {
console.log("Request handler 'home' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<h1>Welcome to College</h2>'+
'<p>Where would you like to visit?</p>'+
'<ul>'+
'<li>Colleges</li>'+
'<li>Hours of Operation</li>'+
'<li>Upload a Photo</li>'+
'<li>View Gallery</li>'+
'</ul>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function colleges(response) {
console.log("Request handler 'colleges' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<h1>Colleges</h2>'+
'<ul>'+
'<li>A-B Tech</li>'+
'<li>UNC Asheville</li>'+
'<li>UNC Charlotte</li>'+
'<li>Western Carolina</li>'+
'<li>NC State</li>'+
'</ul>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function hours(response) {
console.log("Request handler 'gallery' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<h1>Hours of Operation</h2>'+
'<table>'+
'<tr><td>Monday - Thursday</td><td>9 a.m. - 7 p.m.</td></tr>'+
'<tr><td>Friday</td><td>9 a.m. - 5 p.m.</td></tr>'+
'<tr><td>Saturday</td><td>9 a.m. - 12 p.m.</td></tr>'+
'</table>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function start(response) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<h1>Upload a file</h2>'+
'<p>It will be shown on the /show url after</p>'+
'<form action="/upload" enctype="multipart/form-data" '+
'method="post">'+
'<input type="file" name="upload" multiple="multiple">'+
'<input type="submit" value="Upload file" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, request) {
console.log("Request handler 'upload' was called.");
var form = new formidable.IncomingForm();
console.log("about to parse");
form.parse(request, function(error, fields, files) {
console.log("parsing done");
/* Possible error on Windows systems:
tried to rename to an already existing file */
fs.rename(files.upload.path, "/home/ubuntu/node_stuff/node_assignment/test.jpg", function(err) {
if (err) {
fs.unlink("/home/ubuntu/node_stuff/node_assignment/test.jpg")
fs.rename(files.upload.path, "/home/ubuntu/node_stuff/node_assignment/test.jpg");
}
});
response.writeHead(200, {"Content-Type": "text/html"});
response.write("received image:<br/>");
response.write("<img src='/show' />");
response.end();
});
}
function show(response) {
console.log("Request handler 'show' was called.");
fs.readFile("/home/ubuntu/node_stuff/node_assignment/test.jpg", "binary", function(error, file) {
if(error) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(error + "\n");
response.end();
} else {
response.writeHead(200, {"Content-Type": "image/jpg"});
response.write(file, "binary");
response.end();
}
});
}
exports.start = start;
exports.upload = upload;
exports.show = show;
exports.home = home;
exports.colleges = colleges;
exports.hours = hours;
exports.abtech = abtech;
Any hints about what I am doing wrong would be very much appreciated. My instructor is tough to get a hold of during the weekend, so I don't really have anywhere else to turn. Thank you.
Your colleges variable is already a valid JavaScript Object. You do not have to use JSON.parse on it.
JSON.parse expects a String as first argument, but you provide an Object. Thus it is coerced to a String looking like the one you see in the Error message.
For the rest of your code, you might want to take a look at Express or Zappa to be able to write the code a bit more compact ;)
the solution is to use JSON.stringify as follows
var target=JSON.parse(JSON.stringify(source));