At the end of the previous section we saw some serious
drawbacks in the way we expected our webserver to work.
Here we shall do what it takes to remedy that.
This basically means expanding the routing so that is
aware of the interaction af the browser and the http.
Yet again, following the best practice outlined in
the section called “Project Creation - Best Practice” we create a project, this
time myg62 remotely, clone it, prepare the
package.json, and before we get to the server,
we create a project subdirectory views,
and in that we create a boilerplate index.html.
This time we add a few more directories so that we may
get a good structure in our server environment.
We create a public directory, and inside that
a images, a css, and a js
directory. Other files are copied from the most recent
incarnation. It will look similar to this:
. ├── node_modules │ └── http-status-codes │ ├── LICENSE │ ├── README.md │ ├── index.d.ts │ ├── index.js │ └── package.json ├── public │ ├── css │ │ └── side.css │ ├── images │ │ └── iau_rocks.png │ └── js │ └── side.js ├── views │ ├── index.html │ └── side.html ├── README.md ├── handlers.js ├── main.js ├── package-lock.json ├── package.json ├── router.js └── server.js
Still, the main.js, and the server.js
is unchanged.
The router and the handlers are, as often repeated, project
specific and must therefore be adapted with each project.
This time the router has changed to cater for routes based on
embedded requests such as css, js,
and images. When the browser renders a primary request, eg for
and HTML5 page, it issues requests for the urls it meets in the
rendering.
These requests are recognised by file extensions,
based on the router dissection of the request url.
myg62/main.js, Unchanged!"use strict";
var server = require("./bin/server"); // make server module available
var router = require("./routes/router"); // router module
server.start(router); // start server
// callback to route
myg62/server.js, Unchanged!"use strict";
/*
* new server.js adds request body data
*/
const http = require("http"); // http module
const lib = require("../private/libWebUtil"); // home grown utilities
const hostname = "localhost";
const port = Number(process.argv[2]) || 3000;
module.exports = {
start(router) {
const server = http.createServer();
server.on("request", function (req, res) { // eventhandler for "request"
console.log(lib.makeLogEntry(req)); // home made utility for logging
let body = [];
req.on("data", function (bodyData) { // eventhandling for data reception
body.push(bodyData); // bodyData is an object
});
req.on("end", function () { // eventhandling for end-of-data
body = Buffer.concat(body).toString(); // body2string
router.route(req, res, body); // pass to router
});
});
server.listen(port, hostname, function () {
console.log(`Log: Server started on http://${hostname}:${port}/`);
});
}
}myg62/router.js
"use strict";
/*
* check if routed handler function exists
* if yes call it, else complain
*/
const handlers = require("./handlers"); // handlers module
const requestHandlers = { // application urls here
"/": handlers.home,
"/start": handlers.home,
"/side": handlers.side,
"/notfound": handlers.notfound,
"js": handlers.js,
"css": handlers.css,
"png": handlers.png
}
module.exports = {
route(req, res, body) {
let arr = req.url.split(".");
let ext = arr[arr.length - 1];
if (typeof requestHandlers[req.url] === 'function') { // look for route
requestHandlers[req.url](req, res); // if found use it
} else if (typeof requestHandlers[ext] === "function") {
requestHandlers[ext](req, res);
} else {
console.log("5: " + ext);
requestHandlers["/notfound"](req, res); // use notfound
}
}
}
myg62/handlers.js
'use strict';
/*
* handlers.js
* Requesthandlers to be called by the router mechanism
*/
const fs = require("fs"); // file system access
const httpStatus = require("http-status-codes"); // http sc
module.exports = {
home(req, res) {
let path = "views/index.html";
fs.readFile(path, function(err, data) {
if (err) {
console.log(`Not found file: ${path}.`);
}
res.writeHead(httpStatus.OK, { // yes, write header
"Content-Type": "text/html; charset=utf-8"
});
console.log(`served routed file: ${path}.`);
res.write(data);
res.end();
});
},
side(req, res) {
let path = "views/side.html";
fs.readFile(path, function(err, data) {
if (err) {
console.log(`Not found file: ${path}.`);
}
res.writeHead(httpStatus.OK, { // yes, write header
"Content-Type": "text/html; charset=utf-8"
});
console.log(`served routed file: ${path}.`);
res.write(data);
res.end();
});
},
js(req, res) {
let path = "public/js" + req.url;
fs.readFile(path, function(err, data) {
if (err) {
console.log(`Not found file: ${path}.`);
}
res.writeHead(httpStatus.OK, { // yes, write header
"Content-Type": "application/javascript; charset=utf-8"
});
console.log(`served routed file: ${path}.`);
res.write(data);
res.end();
});
},
css(req, res) {
let path = "public/css" + req.url;
fs.readFile(path, function(err, data) {
if (err) {
console.log(`Not found file: ${path}`);
}
res.writeHead(httpStatus.OK, { // yes, write header
"Content-Type": "text/css; charset=utf-8"
});
console.log(`served routed file: ${path}.`);
res.write(data);
res.end();
});
},
png(req, res) {
let path = "public/images" + req.url;
fs.readFile(path, function(err, data) {
if (err) {
console.log(`Not found file: ${path}`);
}
res.writeHead(httpStatus.OK, { // yes, write header
"Content-Type": "image/png"
});
console.log(`served routed file: ${path}.`);
res.write(data);
res.end();
});
},
notfound(req, res) {
console.log(`Handler 'notfound' was called for route ${req.url}`);
res.end();
}
}
On your CLI do npm test to start the server.
Now we show http://localhost:3000/start and then http://localhost:3000/side to check for the assets in the HTML5.