Designing a server script in Node.JS - node.js

I'm trying to figure out a few simple best practices when it comes to structuring a nodeJS server object. Please note that I'm coming from a LAMP background, so the whole thing is somewhat of a paradigm shift for me.
Static Content
Static content has documented examples, and works like a charm:
var http = require('http'),
url = require('url'),
fs = require('fs'),
sys = require(process.binding('natives').util ? 'util' : 'sys');
server = http.createServer(function(req, res){
var parsedURL = url.parse(req.url, true);
var path = parsedURL.pathname;
var query = parsedURL.query;
switch (path){
case '/':
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Greetings!</h1>');
res.end();
break;
default:
fs.readFile(__dirname + path, function(err, data){
if (err) return send404(res);
res.writeHead(200, {'Content-Type':'text/html'})
res.write(data, 'utf8');
res.end();
});
}
}).listen(80);
send404 = function(res){
res.writeHead(404);
res.write('404');
res.end();
};
The server listens for requests, looks up the files, and shoots the content of those files back to the client. Obviously the example I gave is quite dumb and doesn't account for files that aren't text/html, but you get the idea.
Dynamic Content
But what if we don't want to serve static content? What if we want to, for instance, have a hello world file which takes in a value from the querystring and responds differently.
My first guess is that I should create a second file using the nodeJS module setup, give it some module methods which take in information, and just concatenate a crap load of strings together.
For instance, a hello world module called hello.js:
exports.helloResponse = function( userName ) {
var h = "<html>";
h += "<head><title>Hello</title></head>";
h += "<body>Hello, " + userName +"</body>";
h += "</html>";
}
and then add the following case to the server handler:
case 'hello':
res.writeHead(200, {'Content-Type':'text/html'})
res.write(require("./hello.js").helloResponse(query["userName"]), 'utf8');
res.end();
I'm OK with the module, but I hate the fact that I have to create a giant concatenated string in javascript. Does the S.O. community have any ideas? What approaches have you taken to this situation?

Node.js is a "bare bones" platform (not unlike Python or Ruby), which makes it very flexible.
You will benefit from using Node.js with a web framework such as Express.js to handle the grunt work. Express.js uses another module, Connect.js, to provide routing, configuration, templating, static file serving, and more.
You will also want a template language. EJS, for example, gives you a PHP/JSP-style templating language, while Jade provides a Haml-esque approach.
Explore the list of frameworks and templating engines on the Node.js modules page and see which you prefer.

Node.js is not bare bones any more. Use a framework of you choice. Take a look at least at express and socketstream frameworks. Also take a look at socket.io as a replacement for AJAX.

Related

nodejs url parse returns an extra undefined object

I'm writing a node js script to pull variables from the url line.
var http = require('http');//http package
var url = require('url');// url package
var server = http.createServer(function(req, res){// creates server
res.writeHead(200, {'Content-Type': 'text/html'});
var q = url.parse(req.url, true).query//pulls apart the url
var temp = q.temp;
res.write(temp);
console.log(q.temp);
res.end();
}).listen(7474)
Whenever it's tested, the script returns an extra variable of some kind. If I feed it http://localhost:7474/?temp=29 I get:
29
undefined
inside of my console. For some of my other functions in this script it causes the whole system to crash. And failure as
The first argument must be one of type string or Buffer. Received type undefined
Why is that? And how do I remedy the situation?
You should use res.write() again followed by res.end(). The latter isn't supposed to return data.
Though it can supposedly return a string value in the first argument and then define the encoding format of the string as the second argument, but I've never tried that...
"If data is specified, it is equivalent to calling response.write(data, encoding) followed by response.end(callback)."
https://nodejs.org/api/http.html#http_response_end_data_encoding_callback
var http = require('http');//http package
var url = require('url');// url package
var list = ['0', '0', '1', '0'];
var server = http.createServer(function(req, res){// creates server
res.writeHead(200, {'Content-Type': 'text/html'});
var q = url.parse(req.url, true).query//pulls apart the url
var temp = q.temp;
res.write(temp);
console.log(q.temp);
res.write(list[2] ); //testing artifact displayes them on a browser
res.end();
}).listen(7474)
In you case there is really no reason to have both calls to .write() so I would just combine them...
res.write(JSON.stringify([ temp, list[2] ]));
Or
res.write(JSON.stringify({ temp, listItem:list[2] }));
EDIT:
After running this code myself you have a different issue here, which is giving you those confusing errors. Try this for now ...
var http = require('http');//http package
var url = require('url');// url package
var list = ['0', '0', '1', '0'];
var server = http.createServer(function(req, res){// creates server
if (req.url === '/favicon.ico') {
res.writeHead(204);
res.end();
} else {
res.writeHead(200, {'Content-Type': 'text/html'});
var q = url.parse(req.url, true).query//pulls apart the url
var temp = q.temp;
res.write(temp);
res.write(list[2]); //testing artifact displayes them on a browser
res.end();
}
}).listen(7474)
server.on('listening', function() {
console.log('listening on port 7474')
});
The browser was making a 'default' request to favicon.ico after the page initial page loaded to do just that-load the favicon for each web page. That request will crash your program because it doesn't include the query parameter `?temp=, which you aren't currently checking for.
The solution I provided is not workable solution for a production application, but this is clearly a little demo project, so it should do the job for your use case.
If you want to develop a larger, stable, production application you are going to have to reorganize things quite a bit. This could be a starting point if you don't want to use a framework...
https://adityasridhar.com/posts/how-to-use-nodejs-without-frameworks-and-external-libraries
I use the Express framework for all my node apps, which makes some of the default configuration faster and there are thousands of tutorials online to get you started...
https://medium.com/#purposenigeria/build-a-restful-api-with-node-js-and-express-js-d7e59c7a3dfb
I just Googled these tutorials as an example, but you should do your own research to find the most suitable.

Node.js - socket.io web app

I've created a basic node.js server program and used socket.io to pass some field data from a client (see below). Pretty chuffed as I'm new to this business. I liked this node-express-socket.io approach as its all Javascript and is apparently usable by most browsers (incl' mobile). The problem is I've kind of fumbled my way through and do not not fully understand what I have created! Two questions...
1) Do I need to use the "//ajax.googleapis.com...jquery..."? This is annoying as the browser will need to have an internet connection to work. Is there another way to access the html doc elements without needing an internet connection?
2) What does the "app.use(express.static...." line do? The "app.get..." function seems to require this to work.
If there are any other general comments about my code please let me have it!
Cheers,
Kirbs
Client side code:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect(document.location.protocol+'//'+document.location.host);
function clicked(){
$(function(){
var makeInput=$('.app').find('#make').val();
var modelInput=$('.app').find('#model').val();
socket.emit('make', makeInput);
socket.emit('model', modelInput);
});
};
</script>
Server side code:
var express = require('express');
var http = require('http');
var socketio = require('socket.io');
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.on('make', function (make) {
socket.on('model',function (model){
console.log('recieved message:', make+','+model);
});
});
});
server.listen(8000);
1) As you have setup a static web server (see answer 2), you could simply download the jquery source and serve the .js file from there.
2) "app.use(express.static...." configure a static webserver and setting up the http root directory to the directory that your node.js script lives, as indicated by the __dirname variable. For more detail, see app.use API reference.
As result, I would recommend you change you app.use to:
app.use(express.static(__dirname + '/public'));
and place all your static files, including your jquery file(s), under a public subdirectory.
Also, your server side code has a dependency on sequence of make and model which should be changed. For example, if you switch the emit order to model then make, you should see that your server's console.log will be picking up the make from the previous call.
Instead, try something like:
// On server:
socket.on('info', function (info) {
console.log('recieved message:', info.make+','+info.model);
});
// On client:
socket.emit('info', { make: makeInput, model: modelInput })
1) You can serve the jQuery library also from your server if you like that better. You should put it in the public/vendor or public/js folder in your project.
2) This is a middleware call from Express framework, which uses in turn the Connect middleware stack. Read up on this here.

nodejs web root

I was under the impression that when you run a nodejs webserver the root of the web is the folder containing the js file implementing the webserver. So if you have C:\foo\server.js and you run it, then "/" refers to C:\foo and "/index.htm" maps to C:\foo\index.htm
I have a file server.js with a sibling file default.htm, but when I try to load the contents of /default.htm the file is not found. An absolute file path works.
Where is "/" and what controls this?
Working up a repro I simplified it to this:
var fs = require('fs');
var body = fs.readFileSync('/default.htm');
and noticed it's looking for this
Error: ENOENT, no such file or directory 'C:\default.htm'
So "/" maps to C:\
Is there a way to control the mapping of the web root?
I notice that relative paths do work. So
var fs = require('fs');
var body = fs.readFileSync('default.htm');
succeeds.
I believe my confusion arose from the coincidental placement of my original experiment's project files at the root of a drive. This allowed references to /default.htm to resolve correctly; it was only when I moved things into a folder to place them under source control that this issue was revealed.
I will certainly look into express, but you haven't answered my question: is it possible to remap the web root and if so how?
As a matter of interest this is server.js as it currently stands
var http = require('http');
var fs = require('fs');
var sys = require('sys');
var formidable = require('formidable');
var util = require('util');
var URL = require('url');
var QueryString = require('querystring');
var mimeMap = { htm : "text/html", css : "text/css", json : "application/json" };
http.createServer(function (request, response) {
var body, token, value, mimeType;
var url = URL.parse(request.url);
var path = url.pathname;
var params = QueryString.parse(url.query);
console.log(request.method + " " + path);
switch (path) {
case "/getsettings":
try {
mimeType = "application/json";
body = fs.readFileSync("dummy.json"); //mock db
} catch(exception) {
console.log(exception.text);
body = exception;
}
break;
case "/setsettings":
mimeType = "application/json";
body="{}";
console.log(params);
break;
case "/":
path = "default.htm";
default:
try {
mimeType = mimeMap[path.substring(path.lastIndexOf('.') + 1)];
if (mimeType) {
body = fs.readFileSync(path);
} else {
mimeType = "text/html";
body = "<h1>Error</h1><body>Could not resolve mime type from file extension</body>";
}
} catch (exception) {
mimeType = "text/html";
body = "<h1>404 - not found</h1>" + exception.toString();
}
break;
}
response.writeHead(200, {'Content-Type': mimeType});
response.writeHead(200, {'Cache-Control': 'no-cache'});
response.writeHead(200, {'Pragma': 'no-cache'});
response.end(body);
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
I'm not completely certain what you mean by "routes" but I suspect that setsettings and getsettings are the sort of thing you meant, correct me if I'm wrong.
Nodejs does not appear to support arbitrary mapping of the web root.
All that is required is to prepend absolute web paths with a period prior to using them in the file system:
var URL = require('url');
var url = URL.parse(request.url);
var path = url.pathname;
if (path[0] == '/')
path = '.' + path;
While you're correct that the root of the server is the current working directory Node.js won't do a direct pass-through to the files on your file system, that could be a bit of a security risk after all.
Instead you need to provide it with routes that then in turn provide content for the request being made.
A simple server like
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
Will just capture any request and respond in the same way (but doesn't read the file system).
Now if you want to serve out file contents you need to specify some way to read that file into the response stream, this can be done a few ways:
You can use the fs API to find the file on disk, read its contents into memory and then pipe them out to the response. This is a pretty tedious approach, especially when you start getting a larger number of files, but it does allow you very direct control over what's happening in your application
You can use a middleware server like express.js, which IMO is a much better approach to do what you're wanting to do. There's plenty of questions and answers on using Express here on StackOverflow, this is a good example of a static server which is what you talk about
Edit
With the clarification of the question the reason:
var body = fs.readFileSync('/default.htm');
Results in thinking the file is at C:\default.htm is because you're using an absolute path not a relative path. If you had:
var body = fs.readFileSync('./default.htm');
It would then know that you want to operate relative to the current working directory. / is from the root of the partition and ./ is from the current working directory.

Using Node.js as a simple web server

I want to run a very simple HTTP server. Every GET request to example.com should get index.html served to it but as a regular HTML page (i.e., same experience as when you read normal web pages).
Using the code below, I can read the content of index.html. How do I serve index.html as a regular web page?
var http = require('http');
var fs = require('fs');
var index = fs.readFileSync('index.html');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(index);
}).listen(9615);
One suggestion below is complicated and requires me to write a get line for each resource (CSS, JavaScript, images) file I want to use.
How can I serve a single HTML page with some images, CSS and JavaScript?
Simplest Node.js server is just:
$ npm install http-server -g
Now you can run a server via the following commands:
$ cd MyApp
$ http-server
If you're using NPM 5.2.0 or newer, you can use http-server without installing it with npx. This isn't recommended for use in production but is a great way to quickly get a server running on localhost.
$ npx http-server
Or, you can try this, which opens your web browser and enables CORS requests:
$ http-server -o --cors
For more options, check out the documentation for http-server on GitHub, or run:
$ http-server --help
Lots of other nice features and brain-dead-simple deployment to NodeJitsu.
Feature Forks
Of course, you can easily top up the features with your own fork. You might find it's already been done in one of the existing 800+ forks of this project:
https://github.com/nodeapps/http-server/network
Light Server: An Auto Refreshing Alternative
A nice alternative to http-server is light-server. It supports file watching and auto-refreshing and many other features.
$ npm install -g light-server
$ light-server
Add to your directory context menu in Windows Explorer
reg.exe add HKCR\Directory\shell\LightServer\command /ve /t REG_EXPAND_SZ /f /d "\"C:\nodejs\light-server.cmd\" \"-o\" \"-s\" \"%V\""
Simple JSON REST server
If you need to create a simple REST server for a prototype project then json-server might be what you're looking for.
Auto Refreshing Editors
Most web page editors and IDE tools now include a web server that will watch your source files and auto refresh your web page when they change.
I use Live Server with Visual Studio Code.
The open source text editor Brackets also includes a NodeJS static web server. Just open any HTML file in Brackets, press "Live Preview" and it starts a static server and opens your browser at the page. The browser will auto refresh whenever you edit and save the HTML file. This especially useful when testing adaptive web sites. Open your HTML page on multiple browsers/window sizes/devices. Save your HTML page and instantly see if your adaptive stuff is working as they all auto refresh.
Web / SPA / PWA / Mobile / Desktop / Browser Ext Web Developers
Some SPA frameworks include a built in version of the Webpack DevServer that can detect source file changes and trigger an incremental rebuild and patch (called hot reloading) of your SPA or PWA web app. Here's a few popular SPA frameworks that can do this.
VueJS Developers
For VueJS developers, a favorite is Quasar Framework that includes the Webpack DevServer out of the box with switches to support server-side rendering (SSR) and proxy rules to cure your CORS issues. It includes a large number of optimized components designed to adapt for both Mobile and Desktop. These allows you to build one app for ALL platforms (SPA, SPA+SSR, PWA, PWA+SSR, Cordova and Capacitor Mobile AppStore apps, Electron Desktop Node+VueJS apps and even Browser extensions).
Another popular one is NuxtJS that also supports static HTML/CSS code generation as well as SSR or no-SSR build modes with plugins for other UI component suites.
React Framework Developers
ReactJS developers can also setup hot reloading.
Cordova/Capacitor + Ionic Framework Developers
Iconic is a mobile only hybrid component framework that now supports VueJS, React and Angular development. A local server with auto refresh features is baked into the ionic tool. Just run ionic serve from your app folder. Even better ... ionic serve --lab to view auto-refreshing side by side views of both iOS and Android.
Note: This answer is from 2011. However, it is still valid.
You can use Connect and ServeStatic with Node.js for this:
Install connect and serve-static with NPM
$ npm install connect serve-static
Create server.js file with this content:
var connect = require('connect');
var serveStatic = require('serve-static');
connect()
.use(serveStatic(__dirname))
.listen(8080, () => console.log('Server running on 8080...'));
Run with Node.js
$ node server.js
You can now go to http://localhost:8080/yourfile.html
Check out this gist. I'm reproducing it here for reference, but the gist has been regularly updated.
Node.JS static file web server. Put it in your path to fire up servers in any directory, takes an optional port argument.
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs"),
port = process.argv[2] || 8888;
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
fs.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
response.writeHead(200);
response.write(file, "binary");
response.end();
});
});
}).listen(parseInt(port, 10));
console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
Update
The gist does handle css and js files. I've used it myself. Using read/write in "binary" mode isn't a problem. That just means that the file isn't interpreted as text by the file library and is unrelated to content-type returned in the response.
The problem with your code is you're always returning a content-type of "text/plain". The above code does not return any content-type, but if you're just using it for HTML, CSS, and JS, a browser can infer those just fine. No content-type is better than a wrong one.
Normally the content-type is a configuration of your web server. So I'm sorry if this doesn't solve your problem, but it worked for me as a simple development server and thought it might help some other people. If you do need correct content-types in the response, you either need to explicitly define them as joeytwiddle has or use a library like Connect that has sensible defaults. The nice thing about this is that it's simple and self-contained (no dependencies).
But I do feel your issue. So here is the combined solution.
var http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs")
port = process.argv[2] || 8888;
http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname
, filename = path.join(process.cwd(), uri);
var contentTypesByExtension = {
'.html': "text/html",
'.css': "text/css",
'.js': "text/javascript"
};
fs.exists(filename, function(exists) {
if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"});
response.write("404 Not Found\n");
response.end();
return;
}
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
fs.readFile(filename, "binary", function(err, file) {
if(err) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(err + "\n");
response.end();
return;
}
var headers = {};
var contentType = contentTypesByExtension[path.extname(filename)];
if (contentType) headers["Content-Type"] = contentType;
response.writeHead(200, headers);
response.write(file, "binary");
response.end();
});
});
}).listen(parseInt(port, 10));
console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
You don't need express. You don't need connect. Node.js does http NATIVELY. All you need to do is return a file dependent on the request:
var http = require('http')
var url = require('url')
var fs = require('fs')
http.createServer(function (request, response) {
var requestUrl = url.parse(request.url)
response.writeHead(200)
fs.createReadStream(requestUrl.pathname).pipe(response) // do NOT use fs's sync methods ANYWHERE on production (e.g readFileSync)
}).listen(9615)
A more full example that ensures requests can't access files underneath a base-directory, and does proper error handling:
var http = require('http')
var url = require('url')
var fs = require('fs')
var path = require('path')
var baseDirectory = __dirname // or whatever base directory you want
var port = 9615
http.createServer(function (request, response) {
try {
var requestUrl = url.parse(request.url)
// need to use path.normalize so people can't access directories underneath baseDirectory
var fsPath = baseDirectory+path.normalize(requestUrl.pathname)
var fileStream = fs.createReadStream(fsPath)
fileStream.pipe(response)
fileStream.on('open', function() {
response.writeHead(200)
})
fileStream.on('error',function(e) {
response.writeHead(404) // assume the file doesn't exist
response.end()
})
} catch(e) {
response.writeHead(500)
response.end() // end the response so browsers don't hang
console.log(e.stack)
}
}).listen(port)
console.log("listening on port "+port)
I think the part you're missing right now is that you're sending:
Content-Type: text/plain
If you want a web browser to render the HTML, you should change this to:
Content-Type: text/html
Step1 (inside command prompt [I hope you cd TO YOUR FOLDER]) : npm install express
Step 2: Create a file server.js
var fs = require("fs");
var host = "127.0.0.1";
var port = 1337;
var express = require("express");
var app = express();
app.use(express.static(__dirname + "/public")); //use static files in ROOT/public folder
app.get("/", function(request, response){ //root dir
response.send("Hello!!");
});
app.listen(port, host);
Please note, you should add WATCHFILE (or use nodemon) too. Above code is only for a simple connection server.
STEP 3: node server.js or nodemon server.js
There is now more easy method if you just want host simple HTTP server.
npm install -g http-server
and open our directory and type http-server
https://www.npmjs.org/package/http-server
The fast way:
var express = require('express');
var app = express();
app.use('/', express.static(__dirname + '/../public')); // ← adjust
app.listen(3000, function() { console.log('listening'); });
Your way:
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
console.dir(req.url);
// will get you '/' or 'index.html' or 'css/styles.css' ...
// • you need to isolate extension
// • have a small mimetype lookup array/object
// • only there and then reading the file
// • delivering it after setting the right content type
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('ok');
}).listen(3001);
Rather than dealing with a switch statement, I think it's neater to lookup the content type from a dictionary:
var contentTypesByExtension = {
'html': "text/html",
'js': "text/javascript"
};
...
var contentType = contentTypesByExtension[fileExtension] || 'text/plain';
You can just type those in your shell
npx serve
Repo: https://github.com/zeit/serve.
You don't need to use any npm modules to run a simple server, there's a very tiny library called "npm Free Server" for Node:
50 lines of code
Outputs if you are requesting a file or a folder
Gives it a red or green color if it failed or worked
Less than 1KB in size (minified)
Fully commented so you can tweak it as needed
npm-free-server (on GitHub)
This is basically an updated version of the accepted answer for connect version 3:
var connect = require('connect');
var serveStatic = require('serve-static');
var app = connect();
app.use(serveStatic(__dirname, {'index': ['index.html']}));
app.listen(3000);
I also added a default option so that index.html is served as a default.
if you have node installed on you PC probably you have the NPM, if you don't need NodeJS stuff, you can use the serve package for this:
1 - Install the package on your PC:
npm install -g serve
2 - Serve your static folder:
serve <path>
d:> serve d:\StaticSite
It will show you which port your static folder is being served, just navigate to the host like:
http://localhost:3000
I found a interesting library on npm that might be of some use to you. It's called mime(npm install mime or https://github.com/broofa/node-mime) and it can determine the mime type of a file. Here's an example of a webserver I wrote using it:
var mime = require("mime"),http = require("http"),fs = require("fs");
http.createServer(function (req, resp) {
path = unescape(__dirname + req.url)
var code = 200
if(fs.existsSync(path)) {
if(fs.lstatSync(path).isDirectory()) {
if(fs.existsSync(path+"index.html")) {
path += "index.html"
} else {
code = 403
resp.writeHead(code, {"Content-Type": "text/plain"});
resp.end(code+" "+http.STATUS_CODES[code]+" "+req.url);
}
}
resp.writeHead(code, {"Content-Type": mime.lookup(path)})
fs.readFile(path, function (e, r) {
resp.end(r);
})
} else {
code = 404
resp.writeHead(code, {"Content-Type":"text/plain"});
resp.end(code+" "+http.STATUS_CODES[code]+" "+req.url);
}
console.log("GET "+code+" "+http.STATUS_CODES[code]+" "+req.url)
}).listen(9000,"localhost");
console.log("Listening at http://localhost:9000")
This will serve any regular text or image file (.html, .css, .js, .pdf, .jpg, .png, .m4a and .mp3 are the extensions I've tested, but it theory it should work for everything)
Developer Notes
Here is an example of output that I got with it:
Listening at http://localhost:9000
GET 200 OK /cloud
GET 404 Not Found /cloud/favicon.ico
GET 200 OK /cloud/icon.png
GET 200 OK /
GET 200 OK /501.png
GET 200 OK /cloud/manifest.json
GET 200 OK /config.log
GET 200 OK /export1.png
GET 200 OK /Chrome3DGlasses.pdf
GET 200 OK /cloud
GET 200 OK /-1
GET 200 OK /Delta-Vs_for_inner_Solar_System.svg
Notice the unescape function in the path construction. This is to allow for filenames with spaces and encoded characters.
Edit:
Node.js sample app Node Chat has the functionality you want.
In it's README.textfile
3. Step is what you are looking for.
step1
create a server that responds with hello world on port 8002
step2
create an index.html and serve it
step3
introduce util.js
change the logic so that any static file is served
show 404 in case no file is found
step4
add jquery-1.4.2.js
add client.js
change index.html to prompt user for nickname
Here is the server.js
Here is the util.js
var http = require('http');
var fs = require('fs');
var index = fs.readFileSync('index.html');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
// change the to 'text/plain' to 'text/html' it will work as your index page
res.end(index);
}).listen(9615);
I think you where searching for this. In your index.html, simply fill it with normal html code - whatever you want to render on it, like:
<html>
<h1>Hello world</h1>
</html>
The way I do it is to first of all install node static server globally via
npm install node-static -g
then navigate to the directory that contains your html files and start the static server with static.
Go to the browser and type localhost:8080/"yourHtmlFile".
Basically copying the accepted answer, but avoiding creating a js file.
$ node
> var connect = require('connect'); connect().use(static('.')).listen(8000);
Found it very convinient.
Update
As of latest version of Express, serve-static has become a separate middleware. Use this to serve:
require('http').createServer(require('serve-static')('.')).listen(3000)
Install serve-static first.
I use below code to start a simple web server which render default html file if no file mentioned in Url.
var http = require('http'),
fs = require('fs'),
url = require('url'),
rootFolder = '/views/',
defaultFileName = '/views/5 Tips on improving Programming Logic Geek Files.htm';
http.createServer(function(req, res){
var fileName = url.parse(req.url).pathname;
// If no file name in Url, use default file name
fileName = (fileName == "/") ? defaultFileName : rootFolder + fileName;
fs.readFile(__dirname + decodeURIComponent(fileName), 'binary',function(err, content){
if (content != null && content != '' ){
res.writeHead(200,{'Content-Length':content.length});
res.write(content);
}
res.end();
});
}).listen(8800);
It will render all js, css and image file, along with all html content.
Agree on statement "No content-type is better than a wrong one"
from w3schools
it is pretty easy to create a node server to serve any file that is requested, and you dont need to install any packages for it
var http = require('http');
var url = require('url');
var fs = require('fs');
http.createServer(function (req, res) {
var q = url.parse(req.url, true);
var filename = "." + q.pathname;
fs.readFile(filename, function(err, data) {
if (err) {
res.writeHead(404, {'Content-Type': 'text/html'});
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
return res.end();
});
}).listen(8080);
http://localhost:8080/file.html
will serve file.html from disk
var http = require('http');
var fs = require('fs');
var index = fs.readFileSync('index.html');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'html'});
res.end(index);
}).listen(9615);
//Just Change The CONTENT TYPE to 'html'
I'm not sure if this is exactly what you wanted, however, you can try changing:
{'Content-Type': 'text/plain'}
to this:
{'Content-Type': 'text/html'}
This will have the browser client display the file as html instead of plain text.
Express function sendFile does exactly what you need, and since you want web server functionality from node, express comes as natural choice and then serving static files becomes as easy as :
res.sendFile('/path_to_your/index.html')
read more here : https://expressjs.com/en/api.html#res.sendFile
A small example with express web server for node:
var express = require('express');
var app = express();
var path = require('path');
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(8080);
run this, and navigate to http://localhost:8080
To expand on this to allow you to serve static files like css and images, here's another example :
var express = require('express');
var app = express();
var path = require('path');
app.use(express.static(__dirname + '/css'));
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(8080);
so create a subfolder called css, put your static content in it, and it will be available to your index.html for easy reference like :
<link type="text/css" rel="stylesheet" href="/css/style.css" />
Notice relative path in href!
voila!
A slightly more verbose express 4.x version but that provides directory listing, compression, caching and requests logging in a minimal number of lines
var express = require('express');
var compress = require('compression');
var directory = require('serve-index');
var morgan = require('morgan'); //logging for express
var app = express();
var oneDay = 86400000;
app.use(compress());
app.use(morgan());
app.use(express.static('filesdir', { maxAge: oneDay }));
app.use(directory('filesdir', {'icons': true}))
app.listen(process.env.PORT || 8000);
console.log("Ready To serve files !")
Crazy amount of complicated answers here. If you don't intend to process nodeJS files/database but just want to serve static html/css/js/images as your question suggest then simply install the pushstate-server module or similar;
Here's a "one liner" that will create and launch a mini site. Simply paste that entire block in your terminal in the appropriate directory.
mkdir mysite; \
cd mysite; \
npm install pushstate-server --save; \
mkdir app; \
touch app/index.html; \
echo '<h1>Hello World</h1>' > app/index.html; \
touch server.js; \
echo "var server = require('pushstate-server');server.start({ port: 3000, directory: './app' });" > server.js; \
node server.js
Open browser and go to http://localhost:3000. Done.
The server will use the app dir as the root to serve files from. To add additional assets just place them inside that directory.
There are already some great solutions for a simple nodejs server.
There is a one more solution if you need live-reloading as you made changes to your files.
npm install lite-server -g
navigate your directory and do
lite-server
it will open browser for you with live-reloading.
The simpler version which I've came across is as following. For education purposes, it is best, because it does not use any abstract libraries.
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"mp3":"audio/mpeg",
"mp4":"video/mp4",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"};
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname;
var filename = path.join(process.cwd(), uri);
fs.exists(filename, function(exists) {
if(!exists) {
console.log("not exists: " + filename);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('404 Not Found\n');
res.end();
return;
}
var mimeType = mimeTypes[path.extname(filename).split(".")[1]];
res.writeHead(200, {'Content-Type':mimeType});
var fileStream = fs.createReadStream(filename);
fileStream.pipe(res);
}); //end path.exists
}).listen(1337);
Now go to browser and open following:
http://127.0.0.1/image.jpg
Here image.jpg should be in same directory as this file.
Hope this helps someone :)
local-web-server is definitely worth a look! Here's an excerpt from the readme:
local-web-server
A lean, modular web server for rapid full-stack development.
Supports HTTP, HTTPS and HTTP2.
Small and 100% personalisable. Load and use only the behaviour required by your project.
Attach a custom view to personalise how activity is visualised.
Programmatic and command-line interfaces.
Use this tool to:
Build any type of front-end web application (static, dynamic, Single Page App, Progessive Web App, React etc).
Prototype a back-end service (REST API, microservice, websocket, Server Sent Events service etc).
Monitor activity, analyse performance, experiment with caching strategy etc.
Local-web-server is a distribution of lws bundled with a "starter pack" of useful middleware.
Synopsis
This package installs the ws command-line tool (take a look at the usage guide).
Static web site
Running ws without any arguments will host the current directory as a static web site. Navigating to the server will render a directory listing or your index.html, if that file exists.
$ ws
Listening on http://mbp.local:8000, http://127.0.0.1:8000, http://192.168.0.100:8000
Static files tutorial.
This clip demonstrates static hosting plus a couple of log output formats - dev and stats.
Single Page Application
Serving a Single Page Application (an app with client-side routing, e.g. a React or Angular app) is as trivial as specifying the name of your single page:
$ ws --spa index.html
With a static site, requests for typical SPA paths (e.g. /user/1, /login) would return 404 Not Found as a file at that location does not exist. However, by marking index.html as the SPA you create this rule:
If a static file is requested (e.g. /css/style.css) then serve it, if not (e.g. /login) then serve the specified SPA and handle the route client-side.
SPA tutorial.
URL rewriting and proxied requests
Another common use case is to forward certain requests to a remote server.
The following command proxies blog post requests from any path beginning with /posts/ to https://jsonplaceholder.typicode.com/posts/. For example, a request for /posts/1 would be proxied to https://jsonplaceholder.typicode.com/posts/1.
$ ws --rewrite '/posts/(.*) -> https://jsonplaceholder.typicode.com/posts/$1'
Rewrite tutorial.
This clip demonstrates the above plus use of --static.extensions to specify a default file extension and --verbose to monitor activity.
HTTPS and HTTP2
For HTTPS or HTTP2, pass the --https or --http2 flags respectively. See the wiki for further configuration options and a guide on how to get the "green padlock" in your browser.
$ lws --http2
Listening at https://mba4.local:8000, https://127.0.0.1:8000, https://192.168.0.200:8000
Most of the answers above describe very nicely how contents are being served. What I was looking as additional was listing of the directory so that other contents of the directory can be browsed. Here is my solution for further readers:
'use strict';
var finalhandler = require('finalhandler');
var http = require('http');
var serveIndex = require('serve-index');
var serveStatic = require('serve-static');
var appRootDir = require('app-root-dir').get();
var log = require(appRootDir + '/log/bunyan.js');
var PORT = process.env.port || 8097;
// Serve directory indexes for reports folder (with icons)
var index = serveIndex('reports/', {'icons': true});
// Serve up files under the folder
var serve = serveStatic('reports/');
// Create server
var server = http.createServer(function onRequest(req, res){
var done = finalhandler(req, res);
serve(req, res, function onNext(err) {
if (err)
return done(err);
index(req, res, done);
})
});
server.listen(PORT, log.info('Server listening on: ', PORT));
This is one of the fastest solutions i use to quickly see web pages
sudo npm install ripple-emulator -g
From then on just enter the directory of your html files and run
ripple emulate
then change the device to Nexus 7 landscape.
Node.js webserver from scratch
No 3rd-party frameworks; Allows query string; Adds trailing slash; Handles 404
Create a public_html subfolder and place all of your content in it.
Gist: https://gist.github.com/veganaize/fc3b9aa393ca688a284c54caf43a3fc3
var fs = require('fs');
require('http').createServer(function(request, response) {
var path = 'public_html'+ request.url.slice(0,
(request.url.indexOf('?')+1 || request.url.length+1) - 1);
fs.stat(path, function(bad_path, path_stat) {
if (bad_path) respond(404);
else if (path_stat.isDirectory() && path.slice(-1) !== '/') {
response.setHeader('Location', path.slice(11)+'/');
respond(301);
} else fs.readFile(path.slice(-1)==='/' ? path+'index.html' : path,
function(bad_file, file_content) {
if (bad_file) respond(404);
else respond(200, file_content);
});
});
function respond(status, content) {
response.statusCode = status;
response.end(content);
}
}).listen(80, function(){console.log('Server running on port 80...')});

How to use Node.js to build pages that are a mix between static and dynamic content?

All pages on my 5 page site should be output using a Node.js server.
Most of the page content is static. At the bottom of each page, there is a bit of dynamic content.
My node.js code currently looks like:
var http = require('http');
http.createServer(function (request, response) {
console.log('request starting...');
response.writeHead(200, { 'Content-Type': 'text/html' });
var html = '<!DOCTYPE html><html><head><title>My Title</title></head><body>';
html += 'Some more static content';
html += 'Some more static content';
html += 'Some more static content';
html += 'Some dynamic content';
html += '</body></html>';
response.end(html, 'utf-8');
}).listen(38316);
I'm sure there are numerous things wrong about this example. Please enlighten me!
For example:
How can I add static content to the
page without storing it in a string as a variable value with += numerous times?
What is the best practices way to build a small site in Node.js where all pages are a mix between static and dynamic content?
Personally, I'd use a server that has higher level constructs. For instance, take a look at the expressjs framework - http://expressjs.com/
The constructs you'll be interested in from this package are:
Truly static files (assets etc): app.use(express.static(__dirname + '/public'));
A templating language such as jade, mustache, etc:
http://expressjs.com/en/guide/using-template-engines.html
https://github.com/visionmedia/jade/
You'll want to look up 'locals' and 'partials' for embedding small bits of dynamic content in mostly static content
For example in jade:
!!! 5
html(lang="en")
head
title= pageTitle
script(type='text/javascript')
if (foo) {
bar()
}
body
h1 Jade - node template engine
#container
- if (youAreUsingJade)
p You are amazing
- else
p Get on it!
Becomes:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Jade</title>
<script type="text/javascript">
if (foo) {
bar()
}
</script>
</head>
<body>
<h1>Jade - node template engine</h1>
<div id="container">
<p>You are amazing</p>
</div>
</body>
</html>
If you prefer something a little less drastic I would say look at mustache or one of the other engines that looks a bit more like regular-sauce html.
Alternative you can just use jsDOM. This means you have a DOM object you can manipulate on the server to add your dynamic content, then you can just flush the DOM as a HTML file / string
These days the answer is not so straightforward.
If you don't need to be indexed by Google, consider making a single-page application using socket.io and client-side templates such as jQuery Templates. There are even emerging node.js frameworks for this type of architecture, e.g. socketstream.
If you need to be indexed by Google, do you need your dynamic content to be indexed? If yes,
consider using express and server-side templates such as ejs, jade or mustache. Another (discouraged) approach might be to generate XML from JSON on server and use an XSLT front-end.
If you need only static content to be indexed, consider using express on server, but don't generate any dynamic HTML on server. Instead, send your dynamic content in JSON format to client using AJAX or socket.io, and render it using client-side templates such as jQuery Templates.
Don't consider server-side DOM: DOM doesn't scale for complex layouts, you will sink in a sea of selectors and DOM calls. Even client-side developers understood that and implemented client-side templates. A new promising approach is weld library. It offers best of both worlds, but it is not mature yet to be used in production (e.g. simple things like conditional rendering are not supported yet).
One good way is to use a templating engine. You can store the templates as separate files, and the templating engine has the ability to make the content dynamic. Personally I use yajet (http://www.yajet.net/) which is written for the web but works fine with node, and there are numerous template engines for node on npm.
One of the best things I found is to use NodeJS, Express and Mustache...
You can create your HTML pages as you normally would using Mustache syntax for placeholders for your variables {{name}}...
When a user hits your site, express routs the slug to the correct template...
NodeJS get's the file...
NodeJS get's the dataset from a DB...
Run it through Mustache on the server...
Send the completed page to the client...
Here is a scaled back version I wrote on my blog. It's simple but the idea is pretty sound. I use it to quickly deploy pages on my site.
http://devcrapshoot.com/javascript/nodejs-expressjs-and-mustachejs-template-engine
I went this route because I didn't want to learn all of the extra syntax to write a language I already knew (html). It makes more sense and follows more of a true MVC pattern.
First deliver only static HTML files from server to the client. Then use something like AJAX / server.io to serve the dynamic content. IMO Jade is really ugly for writing HTML code and its better to use a template engine.
I did some Google and found some code by this fellow, its good if you are doing it for PoC / learning.
var server = require('./server');
var controller = require("./controller");
var urlResponseHandlers = require("./urlResponseHandlers");
var handle = {};
handle["/"] = urlResponseHandlers.fetch;
handle["/fetch"] = urlResponseHandlers.fetch;
handle["/save"] = urlResponseHandlers.save;
server.start(controller.dispatch, handle);
Here is how the logic for handling URLs is displayed -
var staticHandler = require('./staticHandler');
function dispatch(handler, pathname, req, res) {
console.log("About to dispatch a request for " + pathname);
var content = "Hey " + pathname;
if (typeof handler[pathname] === 'function') {
content += handler[pathname](req);
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.write(content);
res.end();
} else {
console.log("No request handler found for " + pathname);
staticHandler.handleStatic(pathname, res);
}
}
Here is how static files can be handled -
function handleStatic(pageUrl, response) {
var filename = path.join(process.cwd(), pageUrl);
path.exists(filename, function (exists) {
if (!exists) {
console.log("not exists: " + filename);
response.writeHead(404, {
'Content-Type': 'text/html'
});
response.write('404 Not Found\n');
response.end();
return;
}
//Do not send Content type, browser will pick it up.
response.writeHead(200);
var fileStream = fs.createReadStream(filename);
fileStream.on('end', function () {
response.end();
});
fileStream.pipe(response);
return;
});
}
exports.handleStatic = handleStatic;
I liked the idea. All code copied from this link!
.
A solution have found to this, without using any other modules and or other script is to make the calling script into a module and include it with the function require().
With this solution I can use javascript which ever way I want
What I would do is make an ajax call to a nodejs script (www.example.com/path/script.js)
script.js would need to be built like a module with the exports.functionName=function(){...}
After that include it in your webserver function require(pathToTheScript).functionName(res,req)
You will also need to end the response in the functionName(res,req) by doing res.end();

Resources