HTTP Server Basics
Learning Objectives
- By the end of this lesson, you will be able to:
- - Create HTTP servers with Node.js
- - Handle HTTP requests
- - Implement routing
- - Work with request and response objects
- - Build basic web servers
- - Understand HTTP protocol
- - Process different request types
Lesson 29.1: HTTP Server with Node.js
Learning Objectives
By the end of this lesson, you will be able to:
- Create HTTP servers with Node.js
- Handle HTTP requests
- Implement routing
- Work with request and response objects
- Build basic web servers
- Understand HTTP protocol
- Process different request types
Introduction to HTTP Servers
HTTP servers listen for incoming HTTP requests and send responses. Node.js provides the http module to create servers.
What is an HTTP Server?
- Listens: Waits for incoming requests
- Processes: Handles request data
- Responds: Sends response back
- Stateless: Each request is independent
- Protocol: Uses HTTP/HTTPS protocol
Creating HTTP Server
Basic Server
const http = require('http');
// Create server
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
});
// Listen on port
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Server with Options
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
});
server.listen(3000, 'localhost', () => {
console.log('Server running on http://localhost:3000');
});
// Or specify host
server.listen(3000, '0.0.0.0', () => {
console.log('Server running on all interfaces');
});
Server Class
const http = require('http');
const server = http.createServer();
// Handle request event
server.on('request', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!');
});
// Handle connection event
server.on('connection', (socket) => {
console.log('New connection');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});
Handling Requests
Request Object
const http = require('http');
const server = http.createServer((req, res) => {
// Request method
console.log('Method:', req.method);
// Request URL
console.log('URL:', req.url);
// Request headers
console.log('Headers:', req.headers);
// Request body (for POST, PUT, etc.)
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
console.log('Body:', body);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Request received');
});
});
server.listen(3000);
Response Object
const http = require('http');
const server = http.createServer((req, res) => {
// Set status code
res.statusCode = 200;
// Set headers
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Custom-Header', 'my-value');
// Write response
res.write('<h1>Hello, World!</h1>');
res.write('<p>This is a response</p>');
// End response
res.end();
});
server.listen(3000);
Different Response Types
const http = require('http');
const server = http.createServer((req, res) => {
// JSON response
if (req.url === '/api/data') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'Hello', data: [1, 2, 3] }));
return;
}
// HTML response
if (req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Home Page</h1>');
return;
}
// Plain text response
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Default response');
});
server.listen(3000);
Routing
Basic Routing
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;
// Route handling
if (path === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Home Page</h1>');
} else if (path === '/about') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>About Page</h1>');
} else if (path === '/contact') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Contact Page</h1>');
} else {
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end('<h1>404 - Page Not Found</h1>');
}
});
server.listen(3000);
Method-Based Routing
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 method = req.method;
// GET requests
if (method === 'GET') {
if (path === '/users') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 1, name: 'Alice' }]));
} else if (path.startsWith('/users/')) {
const userId = path.split('/')[2];
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: userId, name: 'Alice' }));
}
}
// POST requests
else if (method === 'POST') {
if (path === '/users') {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
const user = JSON.parse(body);
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: Date.now(), ...user }));
});
}
}
// PUT requests
else if (method === 'PUT') {
if (path.startsWith('/users/')) {
const userId = path.split('/')[2];
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
const user = JSON.parse(body);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ id: userId, ...user }));
});
}
}
// DELETE requests
else if (method === 'DELETE') {
if (path.startsWith('/users/')) {
const userId = path.split('/')[2];
res.writeHead(204);
res.end();
}
}
// 404 for other routes
else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
});
server.listen(3000);
Router Helper
const http = require('http');
const url = require('url');
// Simple router
class Router {
constructor() {
this.routes = {};
}
get(path, handler) {
if (!this.routes[path]) {
this.routes[path] = {};
}
this.routes[path].GET = handler;
}
post(path, handler) {
if (!this.routes[path]) {
this.routes[path] = {};
}
this.routes[path].POST = handler;
}
handle(req, res) {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
const route = this.routes[path];
if (route && route[method]) {
route[method](req, res);
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
}
}
}
// Use router
const router = new Router();
router.get('/', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>Home</h1>');
});
router.get('/about', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<h1>About</h1>');
});
router.post('/users', (req, res) => {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
res.writeHead(201, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ message: 'User created' }));
});
});
const server = http.createServer((req, res) => {
router.handle(req, res);
});
server.listen(3000);
Request and Response Objects
Request Object Properties
const http = require('http');
const server = http.createServer((req, res) => {
// Method
console.log('Method:', req.method);
// URL
console.log('URL:', req.url);
// Headers
console.log('Headers:', req.headers);
console.log('User-Agent:', req.headers['user-agent']);
console.log('Content-Type:', req.headers['content-type']);
// HTTP Version
console.log('HTTP Version:', req.httpVersion);
// Status Code (response)
console.log('Status Code:', req.statusCode);
// Socket
console.log('Remote Address:', req.socket.remoteAddress);
console.log('Remote Port:', req.socket.remotePort);
res.end('Request logged');
});
server.listen(3000);
Response Object Methods
const http = require('http');
const server = http.createServer((req, res) => {
// Set status code
res.statusCode = 200;
// Set status message
res.statusMessage = 'OK';
// Set header
res.setHeader('Content-Type', 'text/html');
res.setHeader('X-Custom-Header', 'value');
// Set multiple headers
res.writeHead(200, {
'Content-Type': 'text/html',
'X-Custom-Header': 'value'
});
// Write data
res.write('<h1>Hello</h1>');
res.write('<p>World</p>');
// End response
res.end();
// Check if headers sent
console.log('Headers sent:', res.headersSent);
// Get header
const contentType = res.getHeader('Content-Type');
console.log('Content-Type:', contentType);
// Remove header
res.removeHeader('X-Custom-Header');
});
Handling Request Body
const http = require('http');
const server = http.createServer((req, res) => {
// Only handle POST, PUT, PATCH
if (['POST', 'PUT', 'PATCH'].includes(req.method)) {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
try {
// Parse JSON
const data = JSON.parse(body);
console.log('Received data:', data);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: true, data }));
} catch (error) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid JSON' }));
}
});
} else {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('OK');
}
});
server.listen(3000);
Practice Exercise
Exercise: Basic Server
Objective: Practice creating HTTP servers, handling requests, implementing routing, and working with request/response objects.
Instructions:
- Create an HTTP server
- Implement routing
- Handle different request methods
- Practice:
- Creating servers
- Handling requests
- Implementing routing
- Working with request/response objects
Example Solution:
// src/server.js
const http = require('http');
const url = require('url');
// Simple in-memory data store
let users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
// Helper function to parse request body
function parseBody(req) {
return new Promise((resolve, reject) => {
let body = '';
req.on('data', (chunk) => {
body += chunk.toString();
});
req.on('end', () => {
try {
resolve(body ? JSON.parse(body) : {});
} catch (error) {
reject(error);
}
});
req.on('error', reject);
});
}
// Helper function to send JSON response
function sendJSON(res, statusCode, data) {
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
}
// Create server
const server = http.createServer(async (req, res) => {
const parsedUrl = url.parse(req.url, true);
const path = parsedUrl.pathname;
const method = req.method;
const query = parsedUrl.query;
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// Handle OPTIONS (preflight)
if (method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
// Route: GET /
if (path === '/' && method === 'GET') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>Node.js HTTP Server</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
h1 { color: #333; }
.endpoint { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 5px; }
</style>
</head>
<body>
<h1>Node.js HTTP Server</h1>
<p>Welcome to the HTTP server!</p>
<h2>Available Endpoints:</h2>
<div class="endpoint">
<strong>GET /users</strong> - Get all users
</div>
<div class="endpoint">
<strong>GET /users/:id</strong> - Get user by ID
</div>
<div class="endpoint">
<strong>POST /users</strong> - Create new user
</div>
<div class="endpoint">
<strong>PUT /users/:id</strong> - Update user
</div>
<div class="endpoint">
<strong>DELETE /users/:id</strong> - Delete user
</div>
</body>
</html>
`);
return;
}
// Route: GET /users
if (path === '/users' && method === 'GET') {
sendJSON(res, 200, users);
return;
}
// Route: GET /users/:id
if (path.startsWith('/users/') && method === 'GET') {
const userId = parseInt(path.split('/')[2]);
const user = users.find(u => u.id === userId);
if (user) {
sendJSON(res, 200, user);
} else {
sendJSON(res, 404, { error: 'User not found' });
}
return;
}
// Route: POST /users
if (path === '/users' && method === 'POST') {
try {
const body = await parseBody(req);
if (!body.name || !body.email) {
sendJSON(res, 400, { error: 'Name and email are required' });
return;
}
const newUser = {
id: users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1,
name: body.name,
email: body.email
};
users.push(newUser);
sendJSON(res, 201, newUser);
} catch (error) {
sendJSON(res, 400, { error: 'Invalid JSON' });
}
return;
}
// Route: PUT /users/:id
if (path.startsWith('/users/') && method === 'PUT') {
try {
const userId = parseInt(path.split('/')[2]);
const userIndex = users.findIndex(u => u.id === userId);
if (userIndex === -1) {
sendJSON(res, 404, { error: 'User not found' });
return;
}
const body = await parseBody(req);
users[userIndex] = { ...users[userIndex], ...body };
sendJSON(res, 200, users[userIndex]);
} catch (error) {
sendJSON(res, 400, { error: 'Invalid JSON' });
}
return;
}
// Route: DELETE /users/:id
if (path.startsWith('/users/') && method === 'DELETE') {
const userId = parseInt(path.split('/')[2]);
const userIndex = users.findIndex(u => u.id === userId);
if (userIndex === -1) {
sendJSON(res, 404, { error: 'User not found' });
return;
}
users.splice(userIndex, 1);
res.writeHead(204);
res.end();
return;
}
// 404 - Not Found
sendJSON(res, 404, { error: 'Route not found' });
});
// Start server
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log(`Visit http://localhost:${PORT} in your browser`);
});
// package.json
{
"name": "http-server-practice",
"version": "1.0.0",
"description": "HTTP server practice with Node.js",
"main": "src/server.js",
"scripts": {
"start": "node src/server.js",
"dev": "node --watch src/server.js"
},
"keywords": ["nodejs", "http", "server"],
"author": "",
"license": "ISC"
}
Testing the Server:
# Start server
node src/server.js
# Test endpoints (in another terminal or browser)
# GET /users
curl http://localhost:3000/users
# GET /users/1
curl http://localhost:3000/users/1
# POST /users
curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name":"Charlie","email":"charlie@example.com"}'
# PUT /users/1
curl -X PUT http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Alice Updated","email":"alice.updated@example.com"}'
# DELETE /users/1
curl -X DELETE http://localhost:3000/users/1
Expected Output:
- Server running on port 3000
- HTML page at root
- RESTful API endpoints working
- CRUD operations functional
Challenge (Optional):
- Add more routes
- Implement authentication
- Add request validation
- Create a complete API
Common Mistakes
1. Not Ending Response
// ❌ Bad: Response never ends
res.writeHead(200);
res.write('Hello');
// ✅ Good: Always end response
res.writeHead(200);
res.end('Hello');
2. Writing After End
// ❌ Bad: Write after end
res.end('Hello');
res.write('World'); // Error
// ✅ Good: Write before end
res.write('Hello');
res.end('World');
3. Not Handling Errors
// ❌ Bad: No error handling
const data = JSON.parse(body);
// ✅ Good: Handle errors
try {
const data = JSON.parse(body);
} catch (error) {
res.writeHead(400);
res.end('Invalid JSON');
}
Key Takeaways
- HTTP Server: Created with http.createServer()
- Request Object: Contains method, URL, headers, body
- Response Object: Used to send responses
- Routing: Handle different paths and methods
- Status Codes: Use appropriate HTTP status codes
- Best Practice: Always end response, handle errors
- Protocol: Understand HTTP methods and status codes
Quiz: HTTP Server
Test your understanding with these questions:
-
http.createServer:
- A) Creates server
- B) Starts server
- C) Both
- D) Neither
-
server.listen:
- A) Creates server
- B) Starts server
- C) Both
- D) Neither
-
req.method:
- A) Request method
- B) Response method
- C) Both
- D) Neither
-
res.end:
- A) Required
- B) Optional
- C) Both
- D) Neither
-
Status code 200:
- A) Success
- B) Error
- C) Both
- D) Neither
-
Status code 404:
- A) Not found
- B) Found
- C) Both
- D) Neither
-
Request body:
- A) Stream
- B) String
- C) Both
- D) Neither
Answers:
- A) Creates server
- B) Starts server
- A) Request method
- A) Required
- A) Success
- A) Not found
- A) Stream (needs to be read)
Next Steps
Congratulations! You've learned HTTP server with Node.js. You now know:
- How to create HTTP servers
- How to handle requests
- How to implement routing
- How to work with request/response objects
What's Next?
- Lesson 29.2: Express.js Framework
- Learn Express.js
- Understand routes and middleware
- Build web applications
Additional Resources
- HTTP Module: nodejs.org/api/http.html
- HTTP Status Codes: developer.mozilla.org/en-US/docs/Web/HTTP/Status
- HTTP Methods: developer.mozilla.org/en-US/docs/Web/HTTP/Methods
Lesson completed! You're ready to move on to the next lesson.
Course Navigation
Node.js Basics
Building Web Servers
- HTTP Server Basics
- HTTP Server with Node.js
- Express.js Framework
- RESTful APIs with Express
Building Web Servers
- HTTP Server Basics
- HTTP Server with Node.js
- Express.js Framework
- RESTful APIs with Express