The HTTP module is foundational to Node.js web servers. Here's a comprehensive guide.
Basic HTTP Server#
1const http = require('http');
2
3const server = http.createServer((req, res) => {
4 // Request info
5 console.log('Method:', req.method);
6 console.log('URL:', req.url);
7 console.log('Headers:', req.headers);
8
9 // Send response
10 res.statusCode = 200;
11 res.setHeader('Content-Type', 'text/plain');
12 res.end('Hello, World!\n');
13});
14
15server.listen(3000, '127.0.0.1', () => {
16 console.log('Server running at http://127.0.0.1:3000/');
17});
18
19// Handle server errors
20server.on('error', (err) => {
21 if (err.code === 'EADDRINUSE') {
22 console.error('Port already in use');
23 } else {
24 console.error('Server error:', err);
25 }
26});Request Handling#
1const http = require('http');
2const url = require('url');
3
4const server = http.createServer((req, res) => {
5 // Parse URL
6 const parsedUrl = url.parse(req.url, true);
7 const pathname = parsedUrl.pathname;
8 const query = parsedUrl.query;
9
10 // Modern URL API
11 const fullUrl = new URL(req.url, `http://${req.headers.host}`);
12 const searchParams = fullUrl.searchParams;
13
14 // Read request body
15 let body = '';
16 req.on('data', (chunk) => {
17 body += chunk.toString();
18 });
19
20 req.on('end', () => {
21 // Parse JSON body
22 let data = null;
23 if (req.headers['content-type'] === 'application/json') {
24 try {
25 data = JSON.parse(body);
26 } catch (e) {
27 res.statusCode = 400;
28 res.end('Invalid JSON');
29 return;
30 }
31 }
32
33 // Handle request
34 handleRequest(req, res, { pathname, query, data });
35 });
36});
37
38function handleRequest(req, res, { pathname, query, data }) {
39 if (req.method === 'GET' && pathname === '/api/users') {
40 res.setHeader('Content-Type', 'application/json');
41 res.end(JSON.stringify({ users: [] }));
42 } else if (req.method === 'POST' && pathname === '/api/users') {
43 res.setHeader('Content-Type', 'application/json');
44 res.statusCode = 201;
45 res.end(JSON.stringify({ created: data }));
46 } else {
47 res.statusCode = 404;
48 res.end('Not Found');
49 }
50}Response Methods#
1const http = require('http');
2
3const server = http.createServer((req, res) => {
4 // Set status code
5 res.statusCode = 200;
6 // Or
7 res.writeHead(200, {
8 'Content-Type': 'application/json',
9 'Cache-Control': 'no-cache',
10 'X-Custom-Header': 'value',
11 });
12
13 // Set individual headers
14 res.setHeader('Content-Type', 'text/html');
15 res.setHeader('Set-Cookie', ['session=abc123', 'user=john']);
16
17 // Check if header was sent
18 if (!res.headersSent) {
19 res.setHeader('X-Late-Header', 'value');
20 }
21
22 // Write body in chunks
23 res.write('First chunk\n');
24 res.write('Second chunk\n');
25
26 // End response
27 res.end('Final chunk\n');
28
29 // Or end with callback
30 res.end('Done', 'utf8', () => {
31 console.log('Response sent');
32 });
33});Routing#
1const http = require('http');
2
3// Simple router
4class Router {
5 constructor() {
6 this.routes = {
7 GET: {},
8 POST: {},
9 PUT: {},
10 DELETE: {},
11 };
12 }
13
14 get(path, handler) {
15 this.routes.GET[path] = handler;
16 }
17
18 post(path, handler) {
19 this.routes.POST[path] = handler;
20 }
21
22 put(path, handler) {
23 this.routes.PUT[path] = handler;
24 }
25
26 delete(path, handler) {
27 this.routes.DELETE[path] = handler;
28 }
29
30 handle(req, res) {
31 const method = req.method;
32 const url = new URL(req.url, `http://${req.headers.host}`);
33 const pathname = url.pathname;
34
35 const handler = this.routes[method]?.[pathname];
36
37 if (handler) {
38 handler(req, res, url);
39 } else {
40 res.statusCode = 404;
41 res.end('Not Found');
42 }
43 }
44}
45
46// Usage
47const router = new Router();
48
49router.get('/', (req, res) => {
50 res.end('Home');
51});
52
53router.get('/api/users', (req, res) => {
54 res.setHeader('Content-Type', 'application/json');
55 res.end(JSON.stringify({ users: [] }));
56});
57
58router.post('/api/users', async (req, res) => {
59 const body = await parseBody(req);
60 res.statusCode = 201;
61 res.end(JSON.stringify({ created: body }));
62});
63
64const server = http.createServer((req, res) => {
65 router.handle(req, res);
66});
67
68// Parse body helper
69function parseBody(req) {
70 return new Promise((resolve, reject) => {
71 let body = '';
72 req.on('data', chunk => body += chunk);
73 req.on('end', () => {
74 try {
75 resolve(JSON.parse(body));
76 } catch {
77 resolve(body);
78 }
79 });
80 req.on('error', reject);
81 });
82}Streaming#
1const http = require('http');
2const fs = require('fs');
3const path = require('path');
4
5const server = http.createServer((req, res) => {
6 if (req.url === '/video') {
7 const videoPath = path.join(__dirname, 'video.mp4');
8 const stat = fs.statSync(videoPath);
9 const fileSize = stat.size;
10 const range = req.headers.range;
11
12 if (range) {
13 // Range request for video streaming
14 const parts = range.replace(/bytes=/, '').split('-');
15 const start = parseInt(parts[0], 10);
16 const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
17 const chunkSize = end - start + 1;
18
19 res.writeHead(206, {
20 'Content-Range': `bytes ${start}-${end}/${fileSize}`,
21 'Accept-Ranges': 'bytes',
22 'Content-Length': chunkSize,
23 'Content-Type': 'video/mp4',
24 });
25
26 const stream = fs.createReadStream(videoPath, { start, end });
27 stream.pipe(res);
28 } else {
29 // Full file
30 res.writeHead(200, {
31 'Content-Length': fileSize,
32 'Content-Type': 'video/mp4',
33 });
34 fs.createReadStream(videoPath).pipe(res);
35 }
36 }
37
38 // Stream large JSON
39 if (req.url === '/large-data') {
40 res.setHeader('Content-Type', 'application/json');
41 res.write('[');
42
43 let first = true;
44 for (let i = 0; i < 10000; i++) {
45 if (!first) res.write(',');
46 first = false;
47 res.write(JSON.stringify({ id: i, data: `Item ${i}` }));
48 }
49
50 res.write(']');
51 res.end();
52 }
53});HTTPS Server#
1const https = require('https');
2const fs = require('fs');
3
4// Read SSL certificates
5const options = {
6 key: fs.readFileSync('private-key.pem'),
7 cert: fs.readFileSync('certificate.pem'),
8 // Optional: CA chain
9 ca: fs.readFileSync('ca-chain.pem'),
10};
11
12const server = https.createServer(options, (req, res) => {
13 res.writeHead(200);
14 res.end('Secure Hello World\n');
15});
16
17server.listen(443, () => {
18 console.log('HTTPS server running on port 443');
19});
20
21// Redirect HTTP to HTTPS
22const http = require('http');
23
24http.createServer((req, res) => {
25 res.writeHead(301, {
26 Location: `https://${req.headers.host}${req.url}`,
27 });
28 res.end();
29}).listen(80);HTTP Client#
1const http = require('http');
2const https = require('https');
3
4// GET request
5function get(url) {
6 return new Promise((resolve, reject) => {
7 const protocol = url.startsWith('https') ? https : http;
8
9 protocol.get(url, (res) => {
10 let data = '';
11 res.on('data', chunk => data += chunk);
12 res.on('end', () => {
13 resolve({
14 statusCode: res.statusCode,
15 headers: res.headers,
16 body: data,
17 });
18 });
19 }).on('error', reject);
20 });
21}
22
23// POST request
24function post(url, data) {
25 return new Promise((resolve, reject) => {
26 const urlObj = new URL(url);
27 const protocol = urlObj.protocol === 'https:' ? https : http;
28 const body = JSON.stringify(data);
29
30 const options = {
31 hostname: urlObj.hostname,
32 port: urlObj.port,
33 path: urlObj.pathname + urlObj.search,
34 method: 'POST',
35 headers: {
36 'Content-Type': 'application/json',
37 'Content-Length': Buffer.byteLength(body),
38 },
39 };
40
41 const req = protocol.request(options, (res) => {
42 let responseData = '';
43 res.on('data', chunk => responseData += chunk);
44 res.on('end', () => {
45 resolve({
46 statusCode: res.statusCode,
47 headers: res.headers,
48 body: responseData,
49 });
50 });
51 });
52
53 req.on('error', reject);
54 req.write(body);
55 req.end();
56 });
57}
58
59// Usage
60async function main() {
61 const getResult = await get('https://api.example.com/users');
62 console.log(getResult);
63
64 const postResult = await post('https://api.example.com/users', {
65 name: 'John',
66 });
67 console.log(postResult);
68}Keep-Alive and Connection Pooling#
1const http = require('http');
2
3// Server with keep-alive
4const server = http.createServer((req, res) => {
5 res.setHeader('Connection', 'keep-alive');
6 res.setHeader('Keep-Alive', 'timeout=5, max=1000');
7 res.end('Hello');
8});
9
10server.keepAliveTimeout = 5000;
11server.headersTimeout = 6000;
12
13// Client with agent for connection pooling
14const agent = new http.Agent({
15 keepAlive: true,
16 keepAliveMsecs: 1000,
17 maxSockets: 10,
18 maxFreeSockets: 5,
19});
20
21function makeRequest() {
22 return new Promise((resolve, reject) => {
23 const req = http.request({
24 hostname: 'localhost',
25 port: 3000,
26 path: '/',
27 agent: agent,
28 }, (res) => {
29 let data = '';
30 res.on('data', chunk => data += chunk);
31 res.on('end', () => resolve(data));
32 });
33
34 req.on('error', reject);
35 req.end();
36 });
37}
38
39// Reuse connections
40async function benchmark() {
41 for (let i = 0; i < 100; i++) {
42 await makeRequest();
43 }
44 console.log('Agent stats:', agent.getCurrentStatus());
45}Middleware Pattern#
1const http = require('http');
2
3// Middleware handler
4function createHandler(middlewares) {
5 return (req, res) => {
6 let index = 0;
7
8 function next(err) {
9 if (err) {
10 res.statusCode = 500;
11 res.end('Internal Server Error');
12 return;
13 }
14
15 const middleware = middlewares[index++];
16 if (middleware) {
17 try {
18 middleware(req, res, next);
19 } catch (e) {
20 next(e);
21 }
22 }
23 }
24
25 next();
26 };
27}
28
29// Example middlewares
30function logger(req, res, next) {
31 console.log(`${req.method} ${req.url}`);
32 next();
33}
34
35function cors(req, res, next) {
36 res.setHeader('Access-Control-Allow-Origin', '*');
37 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
38 next();
39}
40
41function jsonParser(req, res, next) {
42 if (req.headers['content-type'] === 'application/json') {
43 let body = '';
44 req.on('data', chunk => body += chunk);
45 req.on('end', () => {
46 try {
47 req.body = JSON.parse(body);
48 next();
49 } catch {
50 res.statusCode = 400;
51 res.end('Invalid JSON');
52 }
53 });
54 } else {
55 next();
56 }
57}
58
59function handler(req, res) {
60 res.setHeader('Content-Type', 'application/json');
61 res.end(JSON.stringify({ message: 'Hello', body: req.body }));
62}
63
64// Create server with middleware
65const server = http.createServer(
66 createHandler([logger, cors, jsonParser, handler])
67);Server-Sent Events#
1const http = require('http');
2
3const server = http.createServer((req, res) => {
4 if (req.url === '/events') {
5 res.writeHead(200, {
6 'Content-Type': 'text/event-stream',
7 'Cache-Control': 'no-cache',
8 'Connection': 'keep-alive',
9 });
10
11 // Send event every second
12 const interval = setInterval(() => {
13 const data = JSON.stringify({
14 time: new Date().toISOString(),
15 value: Math.random(),
16 });
17 res.write(`data: ${data}\n\n`);
18 }, 1000);
19
20 // Named events
21 setInterval(() => {
22 res.write(`event: ping\n`);
23 res.write(`data: ${Date.now()}\n\n`);
24 }, 5000);
25
26 // Clean up on close
27 req.on('close', () => {
28 clearInterval(interval);
29 });
30 }
31});
32
33server.listen(3000);Best Practices#
Server Setup:
✓ Handle errors properly
✓ Set appropriate timeouts
✓ Use keep-alive for performance
✓ Configure headers securely
Request Handling:
✓ Validate input data
✓ Parse body asynchronously
✓ Handle errors in body parsing
✓ Use streaming for large data
Response:
✓ Set correct Content-Type
✓ Use appropriate status codes
✓ Stream large responses
✓ Handle back-pressure
Security:
✓ Use HTTPS in production
✓ Set security headers
✓ Validate request size
✓ Rate limit requests
Conclusion#
The Node.js HTTP module provides low-level control over HTTP servers and clients. Use it for learning HTTP fundamentals or building custom solutions. For production apps, consider frameworks like Express or Fastify that build on these primitives.