Module5-NodeJS-TEST
Node.js is a JavaScript runtime built on Chrome's V8 engine that allows JavaScript to run on the server. Frameworks such as Express run on top of Node.js.
Node.js is especially useful for real-time, high-concurrency applications due to its non-blocking, event-driven execution model.
Contents
Non-Blocking I/O
Node.js uses a non-blocking execution model. Instead of waiting for operations (like database queries or file reads) to complete, Node continues executing other work and runs a callback or Promise when the operation finishes.
Blocking example (conceptual):
var data = database.query("select * from news");
print(data[0].title);
The above pseudo-code queries a database, saves the result of the query in a variable named data, and then prints out the first title in data. The problem arises when multiple clients all want to access the server at the same time. In a blocking I/O model, a client must wait until all other clients finish before it can start its process. With intensive operations and thousands of clients, this can easily crash your server!
The solution is to use non-blocking I/O. Consider this revised pseudo-code:
Non-blocking example:
database.query("select * from news", function(data){
print(data[0].title);
});
The revised pseudo-code achieves the same end result as the first version. However, it allows other clients to perform tasks while this process is waiting for the database to be queried! The code occurs in two parts: first, we start the query. Second, when the query is complete, our anonymous callback function is executed. In Node.js, callback functions are usually passed one or more parameters.
Better yet, with non-blocking I/O, you have no concurrency issues, because everything runs in just one thread. Nifty!
Modern Node.js commonly uses async/await instead of callbacks:
const data = await database.query("select * from news");
console.log(data[0].title);
Installing Node.js
We use nvm (Node Version Manager) to install Node:
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
$ source ~/.bashrc
$ nvm install --lts
$ node -v
$ npm -v
Your First Node.js Application
Create a file named hello.js:
import http from "node:http";
http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello World\n");
}).listen(3456);
console.log("Server running at http://localhost:3456/");
Run:
$ node hello.js
Important: Modern Node uses ES Modules. Add this to package.json:
{
"type": "module"
}
Installing Packages with npm
Install dependencies locally:
$ npm install mime
npm automatically records dependencies in package.json.
Static File Server
The following server serves static files from a directory:
import http from "node:http";
import { readFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import path from "node:path";
import mime from "mime";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const STATIC_DIR = "<STATIC DIRECTORY NAME>";
const app = http.createServer(async (req, resp) => {
try {
const urlPath = new URL(req.url, "http://localhost").pathname;
const filename = path.join(__dirname, STATIC_DIR, decodeURIComponent(urlPath));
if (!existsSync(filename)) {
resp.writeHead(404, { "Content-Type": "text/plain" });
resp.end("File not found");
return;
}
const data = await readFile(filename);
const mimetype = mime.getType(filename) || "application/octet-stream";
resp.writeHead(200, { "Content-Type": mimetype });
resp.end(data);
} catch {
resp.writeHead(500);
resp.end("Server error");
}
});
app.listen(3456);
Security Note: Production servers must validate file paths to prevent directory traversal attacks.
Opening Port 3456 on EC2
Follow the same process used previously to open port 80, but create a rule for TCP port 3456.
Node.js Security
Common risks include:
- XSS
- CSRF
- Injection attacks
- Unsafe use of eval()
- Directory traversal
Always validate inputs and sanitize outputs.
Node.js Conventions
Initialize a project:
$ npm init -y
Install dependencies:
$ npm install
package.json stores metadata and dependencies.