Understanding Node.js IncomingMessage in HTTP Servers
In native Node.js development, handling incoming web traffic relies
heavily on the IncomingMessage class, which is instantiated
by http.Server when receiving a request. This article
explains how the IncomingMessage class represents an
incoming HTTP request, outlining its role as a readable stream and
examining its key properties, such as headers, methods, and URLs, along
with practical examples of how to access request data.
What is the IncomingMessage Class?
The IncomingMessage class is created internally by
http.Server (or http.ClientRequest for
client-side responses) and passed as the first argument (commonly named
req) to the 'request' event listener.
Because IncomingMessage inherits from
stream.Readable, it treats the incoming HTTP request body
as a stream of data. This design allows Node.js to handle large payloads
efficiently without consuming excessive memory, as data can be processed
in chunks as it arrives.
Key Properties of IncomingMessage
The IncomingMessage object contains several essential
properties that describe the incoming HTTP request:
req.method: A string representing the HTTP request method sent by the client (e.g.,'GET','POST','PUT','DELETE').req.url: A string containing the request URL path and query parameters (e.g.,/api/users?id=101). It does not include the protocol or host name.req.headers: An object containing the parsed request headers. Node.js automatically converts all header keys to lowercase to simplify lookups (e.g.,req.headers['user-agent']).req.httpVersion: A string indicating the HTTP version sent by the client (typically'1.1'or'2.0').req.socket: The underlyingnet.Socketobject associated with the connection, which can be used to retrieve details like the client’s IP address (req.socket.remoteAddress).
Reading the Request Body
Since IncomingMessage is a readable stream, the request
body (payload) is not immediately available on the req
object. To read the body—such as JSON data sent via a POST request—you
must listen to the 'data' and 'end'
events.
Here is a practical example of how to handle an incoming HTTP request, inspect its properties, and parse the request body:
const http = require('http');
const server = http.createServer((req, res) => {
// 1. Inspect request metadata
const { method, url, headers } = req;
console.log(`Received a ${method} request to ${url}`);
// 2. Read the stream chunks if there is a request body
let bodyChunks = [];
req.on('data', (chunk) => {
bodyChunks.push(chunk);
});
req.on('end', () => {
// Combine chunks and convert them to a string
const bodyString = Buffer.concat(bodyChunks).toString();
// Parse JSON if the Content-Type header matches
let parsedBody = {};
if (headers['content-type'] === 'application/json' && bodyString) {
try {
parsedBody = JSON.parse(bodyString);
} catch (error) {
res.statusCode = 400;
res.end('Invalid JSON');
return;
}
}
// Send a response back to the client
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
message: 'Request processed successfully',
receivedData: parsedBody,
path: url
}));
});
});
server.listen(3000, () => {
console.log('Server is running on port 3000');
});By combining stream events for the request body with metadata
properties like req.url and req.method, the
IncomingMessage class provides all the necessary utilities
to route and process HTTP requests in native Node.js.