Node.js is a JavaScript runtime built on Chrome's V8 engine, designed for server-side development. It utilizes an event-driven, non-blocking I/O model that makes it lightweight and efficient. Many developers compare its performance favorably against traditional server-side technologies.
Node.js shares similar data structures with client-side JavaScript, though there are notable differences. For instance, browser-specific objects like window do not exist in Node.js, which uses the global object instead.
Core Built-in Modules
Node.js provides numerous built-in modules that simplify common server-side tasks:
- http - Creates HTTP servers and handles requests
- fs - File system operations like reading and writing files
- url - URL parsing and manipulation
- querystring - Parses URL query strings in to objects
Building Your First Web Server
Here's a minimal HTTP server implementation using Node.js built-in modules:
const server = http.createServer((request, response) => { response.write("Hello from Node.js server!"); response.end(); });
server.listen(3000, () => { console.log("Server running on port 3000"); });
</div>Running this script and accessing `localhost:3000` in your browser displays the greeting message.
While this basic server works, real applications need to serve actual files. The `request` object providse access to the requested URL path:
<div>```
const http = require("http");
const fs = require('fs');
const server = http.createServer((request, response) => {
const pathname = request.url;
if (pathname === '/index.html') {
fs.readFile("./public/index.html", (error, content) => {
if (error) {
console.error("Error reading file:", error.message);
} else {
response.write(content);
}
response.end();
});
}
if (pathname === '/about.html') {
// Handle other routes similarly
}
});
server.listen(8080);
Unified File and API Handling
A production-ready server should distinguish between static file requests and API endpoints:
const server = http.createServer((request, response) => { const parsedUrl = urlParser.parse(request.url, true); const route = parsedUrl.pathname; const queryParams = parsedUrl.query; const postData = {};
if (route === "/favicon.ico") {
response.end();
return;
}
if (!route.includes("/api")) {
fileSystem.readFile("./www" + route, (err, fileData) => {
if (err) {
console.error("File not found:", route);
response.writeHead(404);
} else {
response.write(fileData);
}
response.end();
});
} else {
let rawData = "";
request.on("data", (chunk) => {
rawData += chunk;
});
request.on("end", () => {
if (rawData) {
Object.assign(postData, queryParser.parse(rawData));
}
console.log("Query Parameters:", queryParams);
console.log("Request Body:", postData);
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify({ status: "success" }));
});
}
});
server.listen(9000, () => { console.log("Server listening on port 9000"); });
</div>This implementation uses a simple convention: routes containing `/api` are treated as API endpoints, while all other routes serve static files from the `./www` directory. POST data is collected in chunks and parsed when the request completes.