Creating an HTTP Server

Difficulty: Beginner

Node.js was built from the ground up to handle networking efficiently. The built-in 'http' module lets you create an HTTP server with just a few lines of code, without installing any external packages. This is the foundation upon which frameworks like Express are built, and understanding it gives you deep insight into how web servers actually work.

The core function is http.createServer(), which takes a request handler callback. This callback receives two arguments: the request object (often called req) which contains information about the incoming HTTP request such as the URL, method, and headers, and the response object (often called res) which you use to send data back to the client. Every HTTP interaction follows this request-response cycle - the client sends a request, your server processes it, and sends back a response.

The response object has several important methods. res.writeHead() sets the HTTP status code and response headers in one call. res.setHeader() sets a single header. res.write() sends a chunk of the response body, and res.end() signals that the response is complete. You must always call res.end() or the client will hang waiting for more data. The status code tells the client how the request was handled - 200 means success, 404 means not found, 500 means server error, and so on.

Headers are key-value pairs that provide metadata about the response. The most important header is Content-Type, which tells the browser how to interpret the response body. For HTML pages you use 'text/html', for plain text 'text/plain', for JSON 'application/json', and for CSS 'text/css'. Setting correct headers is essential for browsers to render your content properly.

After creating the server, you call server.listen() with a port number to start accepting connections. Port numbers range from 0 to 65535, with ports below 1024 typically reserved for system services. Common development ports include 3000, 5000, and 8080. The listen() method takes an optional callback that fires once the server is ready to accept connections.

Code examples

Basic HTTP Server

const http = require('http');

const server = http.createServer((req, res) => {
  // Set status code and headers
  res.writeHead(200, { 'Content-Type': 'text/plain' });

  // Send response body and end
  res.end('Hello, World!');
});

// Start listening on port 3000
server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

This creates the simplest possible HTTP server. Every request to localhost:3000 gets a plain text 'Hello, World!' response with a 200 status code. The callback in listen() confirms the server started successfully.

Serving HTML Content with Headers

const http = require('http');

const server = http.createServer((req, res) => {
  // Log request details
  console.log(`${req.method} ${req.url}`);
  console.log('Headers:', JSON.stringify(req.headers, null, 2));

  // Set multiple headers
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Powered-By', 'Node.js');
  res.statusCode = 200;

  // Send HTML response
  res.end(`
    <!DOCTYPE html>
    <html>
      <head><title>My Node Server</title></head>
      <body>
        <h1>Welcome to Node.js!</h1>
        <p>Request URL: ${req.url}</p>
        <p>Request Method: ${req.method}</p>
      </body>
    </html>
  `);
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

This demonstrates accessing request properties (method, url, headers) and setting response headers individually with setHeader(). The Content-Type is set to 'text/html' so the browser renders the HTML properly instead of displaying raw markup.

Different Status Codes

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Home Page');
  } else if (req.url === '/redirect') {
    // 301 Moved Permanently
    res.writeHead(301, { 'Location': '/' });
    res.end();
  } else if (req.url === '/error') {
    // 500 Internal Server Error
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end('Something went wrong');
  } else {
    // 404 Not Found
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Page Not Found');
  }
});

server.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});

HTTP status codes communicate the result of a request. 2xx codes mean success, 3xx codes mean redirection (the Location header tells the browser where to go), 4xx codes mean client errors, and 5xx codes mean server errors. Always use semantically correct status codes.

Key points

Concepts covered

http.createServer, Request Object, Response Object, Status Codes, Headers, listen()