Node.js is a powerful platform for building server-side applications using JavaScript. One of its core modules is the http module, which provides the capability to create HTTP servers and clients. This chapter will explore the http module in depth, covering everything from basic server creation to advanced techniques. By the end of this chapter, you will have a comprehensive understanding of how to work with the HTTP module in Node.js.
The http
module in Node.js allows you to create web servers and handle HTTP requests and responses. It is a core module, meaning it comes bundled with Node.js and does not require any additional installation.
To use the http
module, you need to require it in your Node.js script:
const http = require('http');
Creating an HTTP server in Node.js is straightforward. You use the http.createServer
method, which takes a callback function that handles incoming requests and sends responses.
const http = require('http');
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
http.createServer(callback)
creates a new HTTP server.req
(request) and res
(response).res.statusCode = 200
sets the HTTP status code to 200 (OK).res.setHeader('Content-Type', 'text/plain')
sets the Content-Type header to ‘text/plain’.res.end('Hello, World!\n')
sends the response body and signals that the response is complete.server.listen(port, hostname, callback)
makes the server listen on the specified port and hostname.
// Output //
Server running at http://127.0.0.1:3000/
The server.listen
method makes the server start listening for incoming connections on the specified port and hostname.
server.listen(3000, () => {
console.log('Server is listening on port 3000');
});
server.listen(3000, callback)
makes the server listen on port 3000.
// Output //
Server is listening on port 3000
Routing allows you to define different endpoints and handle requests differently based on the URL path.
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Home Page\n');
} else if (req.url === '/about') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('About Page\n');
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Page Not Found\n');
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
req.url
to determine the requested URL path./
, it responds with ‘Home Page’./about
, it responds with ‘About Page’.
// Output //
Server running at http://127.0.0.1:3000/
Query parameters are used to pass additional data in the URL. You can parse them using the url
module.
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const queryObject = url.parse(req.url, true).query;
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(queryObject));
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
url.parse(req.url, true)
parses the URL and returns an object. The second argument true
makes it parse the query string into an object.queryObject
contains the parsed query parameters.queryObject
.
// Output //
Server running at http://127.0.0.1:3000/
URL parameters can be extracted from the URL path.
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const trimmedPath = path.replace(/^\/+|\/+$/g, '');
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(`You requested: ${trimmedPath}\n`);
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
url.parse(req.url, true)
parses the URL and returns an object.parsedUrl.pathname
contains the path part of the URL.trimmedPath
removes leading and trailing slashes from the path.
// Output //
Server running at http://127.0.0.1:3000/
Serving static files, such as HTML, CSS, and JavaScript files, can be done using the fs
module to read and send files.
const http = require('http');
const fs = require('fs');
const path = require('path');
const server = http.createServer((req, res) => {
let filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url);
let extname = String(path.extname(filePath)).toLowerCase();
let mimeTypes = {
'.html': 'text/html',
'.js': 'text/javascript',
'.css': 'text/css',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'application/font-woff',
'.ttf': 'application/font-ttf',
'.eot': 'application/vnd.ms-fontobject',
'.otf': 'application/font-otf',
'.svg': 'application/image/svg+xml'
};
let contentType = mimeTypes[extname] || 'application/octet-stream';
fs.readFile(filePath, (error, content) => {
if (error) {
if (error.code == 'ENOENT') {
fs.readFile(path.join(__dirname, 'public', '404.html'), (error, content) => {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content, 'utf-8');
});
} else {
res.writeHead(500);
res.end(`Sorry, check with the site admin for error: ${error.code} ..\n`);
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url)
constructs the file path.path.extname(filePath).toLowerCase()
gets the file extension.mimeTypes
is an object mapping file extensions to MIME types.contentType
is set based on the file extension.fs.readFile(filePath, callback)
reads the file.ENOENT
error), it serves a 404 page.
// Output //
Server running at http://127.0.0.1:3000/
To handle POST requests, you need to parse the request body. This can be done using the data
and end
events on the request object.
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
res.end('Received POST data: ' + body);
});
} else {
res.end('Send a POST request to see the data');
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
data
event to receive chunks of data and appends them to body
.end
event), it sends the response with the received data.
// Output //
Server running at http://127.0.0.1:3000/
To handle form data, you need to parse the request body. This can be done using the querystring
module.
const http = require('http');
const querystring = require('querystring');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
const parsedBody = querystring.parse(body);
res.end('Received Form Data: ' + JSON.stringify(parsedBody));
});
} else {
res.end('Send a POST request to see the data');
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
querystring.parse(body)
method parses the form data into an object.
// Output //
Server running at http://127.0.0.1:3000/
To handle JSON data, you need to parse the request body as JSON.
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
try {
const parsedBody = JSON.parse(body);
res.end('Received JSON Data: ' + JSON.stringify(parsedBody));
} catch (e) {
res.statusCode = 400;
res.end('Invalid JSON');
}
});
} else {
res.end('Send a POST request to see the data');
}
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
JSON.parse(body)
method parses the JSON data into an object.
// Output //
Server running at http://127.0.0.1:3000/
HTTP headers can be set using the setHeader
method on the response object.
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'text/plain');
res.setHeader('X-Custom-Header', 'CustomValue');
res.end('Headers set');
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
res.setHeader('Content-Type', 'text/plain')
sets the Content-Type header.res.setHeader('X-Custom-Header', 'CustomValue')
sets a custom header.
// Output //
Server running at http://127.0.0.1:3000/
HTTP headers can be read using the req.headers
property.
const http = require('http');
const server = http.createServer((req, res) => {
const headers = req.headers;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(headers));
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
req.headers
contains an object with all the request headers.
// Output //
Server running at http://127.0.0.1:3000/
HTTP headers can be read using the req.headers
property.
HTTP GET requests are used to request data from a specified resource. They are often used to retrieve data from a server without making any changes to the server’s state.
const http = require('http');
// Define the options for the GET request
const options = {
hostname: 'jsonplaceholder.typicode.com',
port: 80,
path: '/posts/1',
method: 'GET',
};
// Create the request
const req = http.request(options, (res) => {
let data = '';
// Called when a data chunk is received
res.on('data', (chunk) => {
data += chunk;
});
// Called when the complete response has been received
res.on('end', () => {
console.log('Response from API:');
console.log(JSON.parse(data));
});
});
// Called if there is an error with the request
req.on('error', (e) => {
console.error(`Problem with request: ${e.message}`);
});
// End the request
req.end();
http
module:http
module using const http = require('http');
. This module is built into Node.js and allows us to make HTTP requests.Explanation :
hostname
: The domain name or IP address of the server (jsonplaceholder.typicode.com
in this case).port
: The port number of the server (typically 80 for HTTP).path
: The path of the resource we want to fetch (/posts/1
fetches the post with ID 1).method
: The HTTP method for the request (GET
in this case).http.request(options, callback)
creates an HTTP request with the specified options.callback
function (res)
handles the response from the server.res.on('data', callback)
: This event is fired when a chunk of data is received from the server. We concatenate each chunk to the data
variable.res.on('end', callback)
: This event is fired when the entire response has been received. Here, we parse the accumulated data
as JSON and log it to the console.req.on('error', callback)
: If there is an error with the request, this event handler logs the error message.req.end()
: Finally, we call req.end()
to actually send the request to the server.HTTP POST requests are used to send data to a server to create or update a resource. They are commonly used in form submissions, uploading files, and API interactions where data needs to be sent to the server.
We’ll continue to use the JSONPlaceholder API to demonstrate how to send data using a POST request.
const http = require('http');
// Define the data to be sent in the POST request
const postData = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
});
// Define the options for the POST request
const options = {
hostname: 'jsonplaceholder.typicode.com',
port: 80,
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
};
// Create the request
const req = http.request(options, (res) => {
let data = '';
// Called when a data chunk is received
res.on('data', (chunk) => {
data += chunk;
});
// Called when the complete response has been received
res.on('end', () => {
console.log('Response from API:');
console.log(JSON.parse(data));
});
});
// Called if there is an error with the request
req.on('error', (e) => {
console.error(`Problem with request: ${e.message}`);
});
// Write the data to the request body
req.write(postData);
// End the request
req.end();
http
module is built into Node.js and is required to make HTTP requests.postData
: The data to be sent in the request body, formatted as a JSON string.hostname
: The server’s domain name.port
: The port number (80 for HTTP).path
: The endpoint path.method
: The HTTP method (POST
for sending data).headers
: The headers for the request, including Content-Type
and Content-Length
.http.request(options, callback)
: Creates the request with the specified options and a callback to handle the response (res
).res.on('data', callback)
: Listens for data chunks from the server. Each chunk is appended to the data
variable.res.on('end', callback)
: Listens for the end of the response. When the response is complete, the accumulated data is parsed as JSON and logged.req.on('error', callback)
: Handles any errors that occur during the request.req.write(postData)
: Writes the postData
to the request body.req.end()
: Signals that the request is complete and sends it to the server.When building an HTTP server, you need to handle various types of errors to ensure the server runs smoothly and can recover from unexpected issues. These errors might include network issues, invalid client requests, or internal server problems.
const http = require('http');
// Create the server
const server = http.createServer((req, res) => {
try {
// Simulating an error
if (req.url === '/error') {
throw new Error('Simulated server error');
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, world!\n');
} catch (err) {
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
res.end(`Server Error: ${err.message}\n`);
}
});
// Handle server errors
server.on('error', (err) => {
console.error(`Server error: ${err.message}`);
});
// Start the server
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
http.createServer((req, res) => { ... })
: Creates an HTTP server and provides a callback to handle incoming requests.if (req.url === '/error') { throw new Error('Simulated server error'); }
: Simulates a server error when the /error
endpoint is accessed.try { ... } catch (err) { ... }
: Wraps the request handling code in a try-catch
block to catch any errors.res.statusCode = 500
: Sets the response status code to 500 (Internal Server Error).res.setHeader('Content-Type', 'text/plain')
: Sets the response content type to plain text.res.end(
Server Error: ${err.message}\n)
: Sends the error message as the response body.server.on('error', (err) => { ... })
: Listens for server-level errors and logs them to the console.server.listen(3000, '127.0.0.1', () => { ... })
: Starts the server on port 3000 and logs a message when it is running.Client errors occur when the client sends a malformed request or requests a resource that doesn’t exist. These errors are usually indicated by status codes in the 4xx range, such as 400 (Bad Request) or 404 (Not Found).
const http = require('http');
// Create the server
const server = http.createServer((req, res) => {
// Handle different request paths
if (req.url === '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Welcome to the homepage!\n');
} else if (req.url === '/error') {
// Simulate a client error
req.on('error', (err) => {
res.statusCode = 400;
res.setHeader('Content-Type', 'text/plain');
res.end(`Client Error: ${err.message}\n`);
});
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('No error occurred.\n');
} else {
// Handle 404 Not Found
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('404 Not Found\n');
}
});
// Handle server errors
server.on('error', (err) => {
console.error(`Server error: ${err.message}`);
});
// Start the server
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
if (req.url === '/') { ... } else if (req.url === '/error') { ... } else { ... }
: Checks the request URL and handles different paths.res.statusCode = 200
: Sets the response status code to 200 (OK).res.setHeader('Content-Type', 'text/plain')
: Sets the response content type to plain text.res.end('Welcome to the homepage!\n')
: Sends the response body.req.on('error', (err) => { ... })
: Listens for errors on the client request.res.statusCode = 400
: Sets the response status code to 400 (Bad Request).res.setHeader('Content-Type', 'text/plain')
: Sets the response content type to plain text.res.end(
Client Error: ${err.message}\n)
: Sends the error message as the response body.res.statusCode = 404
: Sets the response status code to 404 (Not Found).res.setHeader('Content-Type', 'text/plain')
: Sets the response content type to plain text.res.end('404 Not Found\n')
: Sends the 404 Not Found message as the response body.server.on('error', (err) => { ... })
: Listens for server-level errors and logs them to the console.server.listen(3000, '127.0.0.1', () => { ... })
: Starts the server on port 3000 and logs a message when it is running.Middleware functions are functions that have access to the request object (req
), the response object (res
), and the next middleware function in the application’s request-response cycle. They can execute code, modify the request and response objects, end the request-response cycle, and call the next middleware function.
const http = require('http');
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
const server = http.createServer((req, res) => {
const next = () => {
res.statusCode = 200;
res.end('Hello, Middleware');
};
logger(req, res, next);
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
logger
is a middleware function that logs the request method and URL.next
function calls the next middleware or the final handler.logger
middleware is called before sending the response.
// Output //
Server running at http://127.0.0.1:3000/
You can use third-party middleware packages like morgan
for logging and body-parser
for parsing request bodies.
const http = require('http');
const morgan = require('morgan');
const finalhandler = require('finalhandler');
const logger = morgan('combined');
const server = http.createServer((req, res) => {
const next = finalhandler(req, res);
logger(req, res, next);
});
server.listen(3000, '127.0.0.1', () => {
console.log('Server running at http://127.0.0.1:3000/');
});
morgan
is a logging middleware.finalhandler
handles the final response.logger
middleware is used to log requests.
// Output //
Server running at http://127.0.0.1:3000/
In this chapter, we covered:
With the knowledge gained from this chapter, you should be well-equipped to handle any HTTP-related tasks in Node.js. Keep experimenting and exploring to master the full potential of the http
module.
The http module in Node.js provides robust capabilities for creating HTTP servers and clients. By understanding the basic and advanced features of this module, you can build a wide range of server-side applications, from simple static file servers to complex web applications handling dynamic content and APIs.Happy coding !❤️