Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Node.js Get Started and Miscellaneous

4.88/5 (12 votes)
5 Mar 2015CPOL21 min read 47.1K   839  
Study note on Node.js
This is a study note on Node.js. I realized that Node.js is a larger topic than I initially thought. I hope I can be concise enough to cover a few interesting aspects in as fewer sentences as possible.

Background

Some time ago, actually a long while ago, I was introduced to Node.js by one of my colleagues and by Youtube. But I was not interested, because they did not advertise it well. They emphasized that we can use JavaScript to write server code, but I never felt that JavaScript has any advantage than the already mature languages like Java and C# in writing server code and I never felt the shortage of the programmers who have mastered these mature languages. Node.js came much later than the thread-based web servers like Tomcat and IIS. I believe if you come late, you need to be significantly different to get accepted. Well, Node.js is different. This is how the Node.js website describes itself:

Node.jsĀ® is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

The "event-driven, non-blocking I/O model" is how Node.js differentiates itself from the thread-based web servers. I am convinced that if used properly, it should be "efficient, and perfect for data-intensive real-time applications that run across distributed devices". It is the time to pick up Node.js and see how it works.

Install Node.js

Although this study note is based on Windows, it should have some reference value to the other environments. We can download the Node.js installation package from its official website. In my case, I downloaded the package "node-v0.12.0-x64.msi" and installed it on my computer. In order not to mess up my "C:\Program Files" folder, I chose to install the Node.js in the "C:\Node" folder.

Image 1

In the installation folder, we can find the two most important files for Node.js.

  • The "node.exe" file is the executable to launch the node applications;
  • The "npm.cmd" file is the "cmd" file to launch the node package manager. Node.js uses dependency injection to find the dependency modules for the programs. The npm is the utility tool to help us to manage the node modules.

Image 2

If you now go to "Control Panel" -> "System" -> "Advanced System Settings" -> "Environment Variables ...", you will find that two folders are added to your path variables by the installation package.

  • The folder "C:\Node" is added to the system path, so we can run "node.exe" and "npm.cmd" from any location in the command prompt window;
  • The folder "C:\Users\song_li\AppData\Roaming\npm" is added to the user path. This is the npm global installation location. If you use npm to install node packages globally, the packages will be installed in this folder. According to the documentation, if you want to use a package in your programs by "require()" it, you should install it locally. But if want to run the package, such as "forever" in the command line, you should install it globally.

If you now issue "node -v" in the command prompt window, you should see the version of the Node.js installed. In my case, it is "v0.12.0". This shows that the Node.js installation is successful.

Find an IDE

Before writing a Node.js application, I will find an IDE. Many IDEs, such as Visual Studio, NetBeans offer Node.js support, but I chose Eclipse, simply because I am using Eclipse right now. The version of Eclipse that I used is "Eclipse Java EE IDE for Web Developers, Kepler Service Release 2" powered by Java 7. If you are using a newer version, I do not think that you will encounter any problem either.

Image 3

To use Eclipse for Node.js, you can install the popular "Enide" plugin. From the Eclipse menu, if you go to "Help" -> "Eclipse Marketplace ..." and search for "Enide", you will find the plugin. Since I have already installed the plugin, I see the "Update" and "Uninstall" button. If you never had the plugin installed, you should see the "Install" button. After installing the "Enide", we have enabled the Node.js support on Eclipse.

The First Node.js Application

With the help of Eclipse and "Enide", creating a Node.js application is indeed very easy. We can create an empty folder as the Eclipse workspace to start Eclipse. From the Eclipse menu, go to "File" -> "New" -> "Project ..." to launch the project wizard.

Image 4

Instead of creating a bare-bone Node.js project, let us create a Node.js Express Project.

Image 5

We can give the project a name and select an HTML template engine to create our first Node.js application.

Image 6

This is a simple yet fully functional web application. The "package.json" file declares the third-party dependencies.

JavaScript
{
  "name": "FirstNodeApplication",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.2.6",
    "ejs": "*"
  }
}

Since we used Express and "ejs" in the project, we can see these two dependencies. If we make changes to the dependencies, we can simply right-click the "package.json" file in Eclipse -> "Run As" -> "npm install" to update the dependency installations in the "node_modules" folder. The "app.js" file is the web application's entry point.

JavaScript
var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path');
    
var app = express();
    
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
    
// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}
    
app.get('/', routes.index);
app.get('/users', user.list);
    
http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

The JavaScript code is fairly self-explanatory, but if you have absolutely no background knowledge on Node.js, the following explanations may help you to understand the code.

  • The global "require()" function is how Node.js loads the modules. If no path information is provided, the module is either a "core module" provided by Node.js itself or a module located in the "node_modules" folder. If path information is provided, Node.js will go to the specified path to find the modules. Within a single Node.js application, modules are singletons.
  • The "app.use()' function configures the Express middlewares. You can go to this link to get more details on the middlewares.
  • The "app.get()" function maps an HTTP request by url pattern to a function in a Node.js module that processes this request.
  • The "http.createServer(app).listen(...)" function starts the web server to listen to the HTTP requests on the specified port.

If you are familiar with either ASP.NET MVC or Spring MVC, you will immediately notice that an Express Node.js application is an MVC application. If we use the MVC terminology, the controllers of the application are in the "routes\index.js" and "routes\user.js" files.

JavaScript
exports.index = function(req, res){
  res.render('index', { title: 'Express' });
};
exports.list = function(req, res){
  res.send("respond with a resource");
};

The MVC view is the "views\index.ejs" file.

HTML
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

If we now right-click the "app.js" file -> "Run As" -> "Node Application", we can start the web application. If we open a browser and type in the correct url, we can see that the Node.js server is running and serving the HTML content.

Image 7

The Express Version Problem

Although the "Enide Studio 2014" helped us to create our first Express Node.js application, it used the Express version 3.2.6. By the time the study note is prepared, the most updated Express is version 4.11.2, so I changed the "package.json" file to use the new version. After running "npm install", I immediately noticed that the application failed to start. As explained by the Express documentation, Express no longer bundles the middleware packages, we will need to install the middlewares by ourselves. So I updated the "package.json" file to install the middlewares.

JavaScript
{
  "name": "FirstNodeApplication",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "4.11.2",
    "ejs": "2.2.4",
    "serve-favicon": "2.2.0",
    "morgan": "1.5.1",
    "body-parser": "1.11.0",
    "method-override": "2.3.1",
    "errorhandler": "1.3.3"
  }
}

I also updated the "app.js" to use the newly installed middlewares.

JavaScript
var express = require('express'),
    fs = require('fs'),
    http = require('http'),
    https = require('https'),
    path = require('path'),
    favicon = require('serve-favicon'),
    morgan = require('morgan'),
    bodyParser = require('body-parser'),
    methodOverride = require('method-override'),
    errorhandler = require('errorhandler');
    
var app = express();
    
// all environments
app.set('httpport', process.env.PORT || 3000);
app.set('httpsport', 3443);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(favicon(__dirname + '/public/favicon.png'));
app.use(morgan('combined'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));
app.use('/public', express.static(path.join(__dirname, 'public')));
    
// development only
if ('development' === app.get('env')) {
    app.use(errorhandler());
}
    
var routes = require('./routes');
var user = require('./routes/user');
app.get('/', routes.index);
app.get('/users', user.list);
    
http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

After re-run "npm install" on the "package.json" file, I can successfully start the Node.js application. Node.js and Express are both quickly evolving. It is not a surprise that the development environment cannot catch up with the changes. But I hope in the future, "Enide" can be updated to use the new version Express.

Node.js Modules and Dependency Injection

Create a Node.js Module

Node.js uses modules to organize the code. According to the documentation, files and modules are in one-to-one correspondence. We can use "exports" to expose data and functions from a Node.js module.

JavaScript
exports.add = function(n1, n2) {
    return n1 + n2;
};
    
exports.substract = function(n1, n2) {
    return n1 - n2;
};
    
exports.multiply = function(n1, n2) {
    return n1 * n2;
};
    
exports.divide = function(n1, n2) {
    return n1 / n2;
};

We can also do it through the "module.exports" object.

JavaScript
module.exports = {
    add: function(n1, n2) {
        return n1 + n2;
    },
    substract: function(n1, n2) {
        return n1 - n2;
    },
    multiply: function(n1, n2) {
        return n1 * n2;
    },
    divide: function(n1, n2) {
        return n1 / n2;
    }
};

It is easy to get confused about the difference between "exports" and "module.exports", until I found this blog post. Instead of repeating what he has blogged, I will simply add the link here. If you are interested, you can take a look at it. You can also carefully review the documentation to get a good understanding on "exports" and "module.exports".

The exports vs module.exports

One of commonly asked questions is the difference between "exports" and "module.exports" in a Node module. Behind the scenes, the pseudo code of the logic to return the object from a Node module by the "require()" function is the following (credit: stackoverflow).

JavaScript
var module = { exports: {} };
var exports = module.exports;

// your code

return module.exports;
  • The "module" object is created at the beginning and it has a property called "exports".
  • The local variable "exports" references the "module.exports" object.
  • The "module.exports" is the object returned by the "require()" function.

The difference between "exports" and "module.exports" results in different behaviors when we implement a Node module.

  • When an object is assign to the "exports" variable, the object is a property of the object returned by the "require()" function;
  • When an object is set to the "module.exports" variable, the object itself is the object returned by the "require()" function.

Require() Node.js Modules

Node.js uses the global function "require('module identifier')" to access the modules. The module identifier is normally a way to specify the file corresponding to the module.

  • If the module identifier passed to the "require()" function does not have a path, the module is either a Node.js core module or a module in the "node_modules" folder. The core modules are defined in node's source in the lib/ folder;
  • If the exact filename is not found, then node will attempt to load the required filename with the added extension of ".js", ".json", and then ".node";
  • In Linux, if the module identifier is prefixed with "/", it is an absolute path to the file;
  • If the module identifier starts with "./" or "../", it is the relative path from the file calling the require() function;
  • If Node.js cannot resolve the module location, require() will throw an Error with its code property set to 'MODULE_NOT_FOUND'.

It is convenient to organize programs and libraries into self-contained folders. In such case, we can add a "package.json" file in the folder.

JavaScript
{ "name" : "some-library",
  "main" : "./lib/some-library.js" }

According to the documentation, if this is in a folder at "./some-library", then require('./some-library') would attempt to load the "./some-library/lib/some-library.js" file. If there is no "package.json" file, Node.js will try to load the "index.js" file in the folder. If there is no "index.js" file, Node.js will attempt to load the "index.node" file in the folder.

Require() Returns Singletons

According to the documentation, modules are cached after the first time they are loaded. This means that every call to the "require()" function will get exactly the same object returned, if it would resolve to the same file. If you want to have a module to execute some code multiple times, then export a function, and call that function.

Get and Post Data

To create a meaningful web application, one of the top questions is how to obtain the data sent through the url and the form post from the browsers.

HTML
<!DOCTYPE html>
<html>
  <head>
    <title>Get & post data</title>
    <link rel='stylesheet' href='/public/stylesheets/style.css' />
  </head>
  <body>
    <h1>Get & post data</h1>
    <form
      action="<%=baseUrl%>getAndPostDataProcessData?parameter1=value1&parameter2=value2" 
      method="POST">
        <div>
            <select name="selection" style="margin: 5px">
                <option value="Data items No.1">Data items No.1</option>
                <option value="Data items No.2">Data items No.2</option>
                <option value="Data items No.3">Data items No.3</option>
            </select>
             <button type="submit">Submit</button>
        </div>
    </form>
  </body>
</html>

The above "ejs" page will send two url parameters and the selection in the dropdown box when the "submit" button is clicked.

JavaScript
var common = require('../common');
    
exports.frontPage = function(req, res) {
    var data = {};
    data.baseUrl = common.baseUrl;
    res.render('getAndPostDataFrontpage', data);
};
    
exports.processData = function(req, res) {
    var data = {};
    data.baseUrl = common.baseUrl;
    
    // Get the url param data
    data.parameter1 = req.query.parameter1;
    data.parameter2 = req.query.parameter2;
    
    // Get the form post data
    data.selection = req.body.selection;
    
    res.render('getAndPostDataProcessData', data);
};
  • The "frontPage" method will load the above "ejs" page;
  • The "processData" method reads the url parameters and the form data and renders the result in another "ejs" file.

We can use the "req.query" object to get the url parameters and the "req.body" object to get the posted data. In order for the "req.body" object to have the posted data, we need to add the Express middleware "body-parser" as a dependency in the "package.json" file and configure it in the app.js file.

JavaScript
var express = require('express'),
    bodyParser = require('body-parser');
    
var app = express();
app.use(bodyParser.urlencoded({ extended: false }));

According to the documentation, if you set "{extended: true}", the body parser will use the "qs" library to parse the data which allows for rich objects and arrays to be encoded. If we now load the page and submit the data, we can see that both the url parameters and the form data are correctly received.

Image 8

Web Session

Most of the web servers support web sessions, so does Node.js. To get the web session support in Express, we need to add the "mssql" as a dependency in the "package.json" file and run "npm install" to install it. We also need to configure the "mssql" middleware in the "app.js" file.

JavaScript
var express = require('express'),
    session = require('express-session');
    
var app = express();
var session_option = {
          secret: 'keyboard cat', resave: false,
          saveUninitialized: true, cookie: { maxAge: null } };
app.use(session(session_option));

In the Express controller, we can use the "req.session" object to access the information in the web session.

JavaScript
exports = module.exports = function(req, res) {
    var accessCount = req.session.accessCount;
    
    if (!accessCount) {
        accessCount = 0;
    }
    accessCount ++;
    
    req.session.accessCount = accessCount;
    res.send('This is your No.' + accessCount
            + ' time to the page in the session');
};

Image 9

If we load the page, it will tell us that it is the No.1 time that we come to the page. If we refresh the page, we can see that the number will add 1 every time.

Cookies

To use cookies in Express, we will need to add the "cookie-parser" in the "package.json" and run "npm install" to install it in the "node_modules" folder. We need to configure the "cookie-parser" in the "app.js" file.

JavaScript
var express = require('express'),
    cookieParser = require('cookie-parser'),
    
var app = express();
app.use(cookieParser());

We can then use cookies in the Express MVC controllers.

JavaScript
exports.action = function(req, res) {
var accessCount = req.cookies.accessCount;
    
    if (!accessCount) {
        accessCount = 0;
    }
    accessCount ++;
    
    res.cookie('accessCount', accessCount, { maxAge: 900000, httpOnly: true });
    res.send('This is your No.' + accessCount
            + ' time to the page in the session');
};

If we load the page in the browser, we can see the access count. Every time we refresh the page, the access count will add 1. Even when we close the browser and restart it, we can find that the access count does not get lost until we reach the specified maximum age.

Image 10

Connect to a Database

Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications. In most of the cases, the data is in a database. Ideally, I should use MongoDB to evaluate Node.js due to the so called "MEAN" stack. But since I have a SQL server database available, I just used this SQL server database to get some flavor of database access in Node.js. You can find the script to create this database from this link. In my environment, I used SQL Server Express 2014. In the script to create the database, I did not grant the database user table level access. If you want to run my example, you need to run the following script to grant the access.

SQL
USE Experiment
GO

GRANT SELECT ON OBJECT::[dbo].[TABLE_FILES] TO FileLoader

In order to connect to a SQL server, we will need to add "mssql" as a dependency in the "package.json" file and run "npm install" to install it.

JavaScript
var sql = require('mssql'); 
    
var config = {
        user: 'FileLoader',
        password: 'Pwd123456',
        server: 'localhost',
        database: 'Experiment',
        options: { encrypt: false }
    };
    
exports.readdata = function(req, res) {
    var connection = new sql.Connection(config);
    
    connection.connect(function(err) {
        if (err) { res.status(500).send(err); return; }
        
        var request = new sql.Request(connection);
        var sqlString = 'SELECT COUNT(*) CT FROM TABLE_FILES';
        
        request.query(sqlString, function(err, rs) {
            connection.close();
            
            if (err) { res.status(500).send(err); return; }
            
            var count = rs[0].CT;
            res.send("There are " + count + " files in the table");
        });
    });
};

In the above Express MVC controller, you should pay some attention to the following:

  • In order not to block the main thread, all the database access code is implemented in callback functions;
  • Every callback function has an "err" parameter to report if there is any error. We need always check this parameter and handle the errors properly. We should never throw any exceptions in the callback functions, because it will crash the thread. In the worst case, it may even crash the whole Node.js server;
  • When we no longer need the connection object, we should close it. I used SQL profiler to watch the connection behavior from Node.js. If we do not close the connection, it will take a long while to get closed, even after the connection object is out of the scope.

Image 11

If we load the web page, it shows that there are four files saved in my database. If you want to repeat my example and if you have not done anything on the database, you should see the number of the files is 0. Working on the database is a large topic. This small example is just to get a taste. Luckily, most of the database drivers have good documentations. You can check out the documentation on MongoDB from this link.

The process.nextTick vs. setImmediate

Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices. It is true that most of the websites are data-intensive. When accessing the data, Node.js will not wait for the data operations to finish. Instead, after scheduling callback functions, it immediately releases the thread for other concurrent requests. When the data operations finish, the callback functions will work on the data and send the responses to the clients. If in any case, we have some CPU intensive operations, we will need to divide the work into smaller pieces. When finishing a piece of work, we will need to schedule the rest of the work in callback functions and release the tread. Otherwise, other concurrent requests will be blocked by this long running monolithic work.

JavaScript
exports = module.exports = function(req, res){
    var data = {};
    data.title = 'process.nextTick vs. setImmediate';
    
    var i = 1;
    setImmediate(function() {
        data.setImmediateExecutionOrder = i++;
        
        if (data.setImmediateExecutionOrder && data.nextTickeExecutionOrder) {
            res.render('nextTickOrSetImmediate', data);
        }
    });
    
    process.nextTick(function() {
        data.nextTickeExecutionOrder = i++;
        
        if (data.setImmediateExecutionOrder && data.nextTickeExecutionOrder) {
            res.render('nextTickOrSetImmediate', data);
        }
    });
};

There are two commonly used ways to schedule the callback functions, "process.nextTick()" and "setImmediate()".

HTML
<!DOCTYPE html>
<html>
  <head>
    <title><%=title%></title>
    <link rel='stylesheet' href='/public/stylesheets/style.css' />
  </head>
  <body>
    <h1><%=title%></h1>
    <div>
        <ul>
            <li>process.nextTick execution order: <%=nextTickeExecutionOrder%></li>
            <li>setImmediate execution order: <%=setImmediateExecutionOrder%></li>
        </ul>
    </div>
  </body>
</html>

If we render the result in the above "ejs" view, we get the following result:

Image 12

We can see that the callback function scheduled by "process.nextTick()" runs before the callback function scheduled by "setImmediate()". According to the documentation:

  • "process.nextTick()" - once the current event loop turn runs to completion, call the callback function.
  • "setImmediate()" - callbacks for immediates are queued in the order in which they were created. The entire callback queue is processed every event loop iteration.

Exceptions in Express

Exceptions are never good things. But compared with the thread-base web servers like Tomcat and IIS, Node.js is much more sensitive to exceptions, because multiple requests are handled by a single thread. If an exception is not properly handled, the thread will die and multiple requests from totally unrelated users will fail.

JavaScript
exports.exceptionInController = function(req, res) {
    throw 'An artificial exception in controller';
    res.send("send some data to the client");
};

exports.exceptionInView = function(req, res) {
    // The exceptionInView.ejs file will throw an exception
    var data = {};
    res.render('exceptionInView', data);
};

exports.exceptionInCallback = function(req, res) {
    setImmediate(function() {
        throw 'An artificial exception in the callback';
        res.send("send some data to the client");
    });
};

If we use MVC terminology, the above controller implemented three action methods. Each of the methods has an artificial exception.

  • "exceptionInController" - the exception happens in the controller
  • "exceptionInView" - the exception happens in the view
  • "exceptionInCallback" - the exception happens in the callback function

The following is the "ejs" view "exceptionInView" that throws the exception.

HTML
<!DOCTYPE html>
<html>
  <head>
    <title>Exception in the view</title>
    <link rel='stylesheet' href='/public/stylesheets/style.css' />
  </head>
  <body>
    <h1>Exception in the view</h1>
    <%=A[1]%>
  </body>
</html>

Since the array "A" is not defined, the embedded code "<%=A[1]%>" will throw an exception. Running the above code, we can find the following:

  • Express and Node.js handle exceptions occur in the controllers and the views.
  • Exceptions occur in the callback functions are not handled by Express and Node.js. If we do not handle these exceptions by ourselves, the thread will crash and die.

Image 13

The above shows that the artificial exception in the controller is handled by Express. But when writing Node.js applications, callback functions will be used extensively. We will need to make all the effort to handle any possible exceptions in the callback functions. If we do not handle them correctly, the thread will crash.

Utilize a Multi-core Computer

As we know, a Node.js application runs on a single thread on a single-core computer. But most modern computers have multiple cores. If we only use a single thread on a multi-core computer, it is a waste of the computation resource. The answer to this question is the "cluster" module. It is a Node.js built-in module. What we need to do is to use the following code to start the server.

JavaScript
// Start the server
var cluster = require('cluster'); 
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {    
    for (var i = 0; i < numCPUs; i++) { cluster.fork(); }
    
    cluster.on('exit', function(deadWorker, code, signal) { cluster.fork(); });
} else {
    http.createServer(app).listen(app.get('httpport'), function(){
        console.log('Express server listening on port ' + app.get('httpport'));
    });
}
  • The "numCPUs" is the number of the CPUs of the computer. For each CPU, we will fork a thread to listen to the HTTP request.
  • The code listens to the 'exit' event of the cluster object. If a thread dies due to an uncaught exception, it will be re-started.

Https Support

As a production ready web server, Node.js has a built-in Https support through its "https" module. Since I prefer a GUI key management tool, I chose the key store explorer to create the private key file and the public certificate file to set up the Https support in this study note. If you have not used key store explorer, you can refer to this link, where I used it to set up the Https support for a Tomcat server.

Image 14

The Node.js does not use key store to keep the key/certificate information, so the type of the key store is not important. But in order to use the key store explorer, I just choose the "PKCS12" anyway.

Image 15

After creating the empty key store, we can right-click on the empty section to add a key pair to the key store. We need to fill in the required information and give the key pair an alias to add it to the key store. In my case, I simply took the default alias "localhost".

Image 16

We can now right click the key pair in the key store explorer -> "Export" -> "Export Private Key" to create a private key file. Please make sure to select the "OpenSSL" key type. The key store explorer will ask us to give the file a name and give it a password. I simply named the file as "localhost.openssl" and set the password as "mypassword" for the experimental purpose.

Image 17

We will also need to right click on the key pair -> "Export" -> "Export Certificate Chain" to get a certificate file. For simplicity, I just took the default file name "localhost.cer". We will need both "localhost.openssl" and "localhost.cer" files to set up the Https support on Node.js. The key store explorer will ask us if we want to save the key store. In this study note, it is not required. But if you want to keep the key store for future reference, you can save it. We can then create a folder in our project and add the two files in the folder and use the following code to start the Node.js server.

JavaScript
// Start the server
var tsloptions = {
        key: fs.readFileSync('./server/localhost.openssl'),
        cert: fs.readFileSync('./server/localhost.cer'),
        passphrase: 'mypassword'
    };
    
var cluster = require('cluster'); 
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {    
    for (var i = 0; i < numCPUs; i++) { cluster.fork(); }
    
    cluster.on('exit', function(deadWorker, code, signal) { cluster.fork(); });
} else {
    https.createServer(tsloptions, app).listen(app.get('httpsport'), function(){
          console.log('Express server ssl listening on port ' + app.get('httpsport'));
    });
}

Image 18

We can then open a browser and type in the correct url to check that the Https support is indeed enabled. Since the certificate is not signed by any certificate authority, the browser will give us a warning before we proceed to the web page. In a production website, you will need to get your certificate signed by a certificate authority to get rid of the annoying warning message.

Forever

As we know, A Node.js thread serves multiple requests. If an unhandled exception happens, the thread will die. In the worst case, the Node.js server dies. We should make all our effort not to allow the exceptions to bring down the server. The "forever" is a tool to run node applications. If the server is down, the forever tool will re-start it.

npm install forever -g

Since we will run forever in the command line, we should install it globally. To start the Node.js server, we can open the windows command prompt and go to the folder that has the Node.js startup JavaScript file. In our "FirstNodeApplication" program, it is the "app.js" file. We can then issue the following command to start the application.

forever start -w app.js

The "-w" option tells forever to reload the application if any file in the application is re-deployed. To stop forever, you can issue the following command:

forever stop app.js

Run Node.js Application as a Service

While "Forever" is a good tool to make sure Node.js applications not to stop, it is ideal that we can run the application as a service. In the Windows environment, we have "node-windows". The documentation has pretty good instructions on how to use it. We can add "node-windows" as a dependency in the "package.json" file and run "npm install" to install it. We can then create a Node.js module to use "node-windows".

JavaScript
var Service = require('node-windows').Service;

// Get the absolute path to the "app.js" file
var apppath = require('path').join(__dirname, 'app.js');

var svc = new Service({
      name:'First Node Application',
      description: 'The First Node Application.',
      script: apppath
    });

svc.on('install',function(){
      svc.start();
    });

exports = module.exports = svc;

We can then create two simple single-line JavaScript files to use this service. One of the JavaScript files is "appinstall.js".

JavaScript
require('./appservice').install();

The other JavaScript file is "appuninstall.js".

JavaScript
require('./appservice').uninstall();

We can issue "node appinstall" to install the Node.js application as a windows service. We can issue this command either from the command prompt window or from within Eclipse by right-clicking the "appinstall.js" file. Upon the successful installation, we can see the service in the service manager.

Image 19

If we now open the browser and type in the correct url, we can see that the application is running.

Image 20

If you want to uninstall the service, you can simply issue the command "node appuninstall". According to the documentation, if you are not using Windows, you can find a version of the "node-windows" for Mac and Linux too.

Expose to Public from Localhost

It may be very useful to let people access a test web site running on your localhost. For this purpose, you can take a look at the https://dashboard.ngrok.com/ (NGROK).

Points of Interest

  • This is a study note on Node.js. I realized that Node.js is a larger topic than I initially thought of. I hope I can be concise enough to cover a few interesting aspects in as fewer sentences as possible.
  • I attached the example project in this study note. If you want to run it, you will need Eclipse version Kepler or above and install the "Enide" plugin. You can then create an empty folder as the Eclipse workspace and use "File" -> "Import ..." -> "General" -> "Existing Projects into Workspace" to import it.
  • If you want to repeat my examples and if you are unable to run the application, one of the common reasons is that you have another instance of the application running on your computer. Since the port number is taken by another instance, the operating system will stop the new instance to start. After you find the running instance and stop it, you should be able to start the new instance.
  • I hope you like my postings and I hope this article can help you in one way or the other.

History

  • 27th February, 2015: First revision

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)