Node.js includes a built-in HTTP module that allows us to create web servers and make HTTP requests without needing third-party libraries.
Understanding the HTTP Module
The HTTP module offers:
- Server-Side Capabilities:
- Create an HTTP server that listens for incoming requests, processes them, and sends back responses.
- Client-Side Capabilities:
- Make HTTP requests to other servers. This is useful for consuming APIs or integrating with external services.
- Event-Driven Model:
- Both servers and clients built with the HTTP module use Node.js's event-driven architecture. This means you can attach event listeners to handle data, errors, and end-of-response events.
The HTTP module is a core part of Node.js, meaning it comes out-of-the-box with no need for installation. Its low-level API provides flexibility for custom server behavior, making it a perfect learning tool before moving on to higher-level frameworks like Express.
Creating an HTTP Server
Let’s start with a simple example to demonstrate how to create an HTTP server using Node.js.
const http = require('http'); // Import the HTTP module
const hostname = '127.0.0.1'; // Localhost address
const port = 3000; // Server will listen on port 3000
// Create a server that responds to every request
const server = http.createServer((req, res) => {
// Set the status code and content type for the response
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
// Send a simple response message
res.end('Hello, World!\n');
});
// Start the server and log that it’s running
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
How It Works:
- Import the Module:
We begin by requiring thehttp
module. - Create the Server:
Usinghttp.createServer()
, we define a callback function that receives the request (req
) and response (res
) objects. This callback is executed every time the server receives an HTTP request. - Set Response Headers and Body:
We set the response status to200 OK
and define theContent-Type
as plain text. Finally, we end the response with a simple message. - Listen for Connections:
The server listens on the specified hostname and port. When ready, it logs a confirmation message.
Handling Different Routes and Response
A more dynamic server often needs to serve different responses based on the URL path. Let’s extend our basic server to handle multiple routes.
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
// Log the request URL for debugging
console.log(`Request for ${req.url} received.`);
// Set up basic routing logic
if (req.url === '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end('<h1>Welcome to the Home Page</h1>');
} else if (req.url === '/about') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end('<h1>About Us</h1><p>This is the about page.</p>');
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found');
}
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
Key Points:
- Route Checking:
The server checks thereq.url
property to determine which route was requested. - Dynamic Responses:
Depending on the route, the server responds with HTML content for the home and about pages, and a plain-text message for unknown routes. - Logging:
Logging incoming requests can be very helpful for debugging and monitoring.
Making HTTP Requests
Apart from serving content, Node.js can act as a client making HTTP requests. The HTTP module provides a method called http.request()
for this purpose
const http = require('http');
// Define request options
const options = {
hostname: 'www.example.com',
port: 80,
path: '/',
method: 'GET'
};
// Create the request
const req = http.request(options, res => {
console.log(`Status Code: ${res.statusCode}`);
// Collect response data in chunks
let data = '';
res.on('data', chunk => {
data += chunk;
});
// When the response is finished, log the complete response
res.on('end', () => {
console.log('Response Body:', data);
});
});
// Handle request errors
req.on('error', error => {
console.error('Request Error:', error);
});
// End the request (this sends it)
req.end();
How It Works:
- Options Object:
Theoptions
object specifies the hostname, port, path, and HTTP method for the request. - Creating the Request:
Thehttp.request()
function returns an instance of theClientRequest
object. We attach event listeners to capture the response. - Event Listeners:
- The
data
event accumulates chunks of data as they arrive. - The
end
event signals that all data has been received. - The
error
event handles any issues during the request.
- The
- Sending the Request:
Callingreq.end()
finalizes and sends the request.