Discuss your project

Setting Up and Testing an HTTP 1.1 Server with Node.js

/* by Tirth Bodawala - July 27, 2024 */
A detailed and abstract illustration representing the setup of an HTTPS 1.1 server with Node.js. The image includes elements such as a server icon

In this tutorial, we’ll walk through the process of setting up an HTTP 1.1 server using Node.js. This server will serve static files and provide a basic understanding of handling HTTP requests and responses.

Prerequisites

  • Node.js (version 20.04 or higher)
  • Basic understanding of JavaScript and Node.js

Step 1: Initialize the Project

Start by creating a new directory for your project and initializing it with npm.

mkdir raw-http-tutorial
cd raw-http-tutorial
npm init -y

This will generate a package.json file. You can update it with the following content:

package name: (tmp) raw-http-tutorial
version: (1.0.0) 
description: Demonstrating Raw HTTP requests and response
entry point: (index.js) src/server/http1.js
test command: 
git repository: 
keywords: 
author: 
license: (ISC)

This will generate a package.json file. You can update it with the following content:

{
  "name": "raw-http-tutorial",
  "version": "1.0.0",
  "description": "Demonstrating Raw HTTP requests and response",
  "main": "src/server/http1.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Tirth Bodawala <[email protected]>",
  "license": "MIT",
  "devDependencies": {},
  "dependencies": {}
}

Step 2: Install Required Packages

Before creating the server, install the necessary packages:

npm install mime-types
npm install --save-dev @types/node @types/mime-types

Step 3: Generate SSL Certificates

HTTPS requires SSL/TLS. Use OpenSSL to generate a self-signed certificate:

mkdir ssl
cd ssl
openssl req -x509 -newkey rsa:2048 -nodes -keyout server-key.pem -out server-cert.pem -days 365

Fill in the required information as follows:

  • Country Name (IN)
  • State or Province Name (Gujarat)
  • Locality Name (Vadodara)
  • Organization Name (Atyantik Technologies)
  • Organizational Unit Name (Development)
  • Common Name (localhost)
  • Email Address ([email protected])

Move the generated files to a directory named ssl.

Step 4: Create the HTTPS 1.1 Server

Create a directory named src and add a file ./src/server/http1.js inside it with the following content:

import { createServer } from 'node:https';
import { createReadStream } from 'node:fs';
import { readFileSync } from 'node:fs';
import { extname, resolve } from 'node:path';
import mime from 'mime-types';
import zlib from 'node:zlib';

const brotliOptions = {
  chunkSize: 32 * 1024,
  params: {
    [zlib.constants.BROTLI_PARAM_QUALITY]: 10,
  },
};

const httpsPort = 8080;
const httpsHost = 'localhost';

// SSL options
const options = {
  key: readFileSync(resolve('ssl', 'server-key.pem')),
  cert: readFileSync(resolve('ssl', 'server-cert.pem'))
};
const html = readFileSync(resolve('src', 'index.html'), { encoding: 'utf-8' });

const httpsServer = createServer(options, async (req, res) => {
  const filePath = resolve(req.url.substring(1));
  if (req.url === '/') {
    res.writeHead(200, {
      'Content-Type': 'text/html',
    });
    res.write(html);
    res.end();
    return;
  }
  try {
    const mimeType = mime.lookup(extname(filePath)) || 'application/octet-stream';

    res.writeHead(200, {
      'Content-Type': mimeType,
      'Content-Encoding': 'br'
    });

    const readStream = createReadStream(filePath);
    const brotliStream = zlib.createBrotliCompress(brotliOptions);
    readStream.pipe(brotliStream).pipe(res);
  } catch (error) {
    console.log(error);
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.write('File not found');
    res.end();
  }
});

httpsServer.listen(httpsPort, httpsHost, () => {
  console.log(`HTTPS server listening on: https://${httpsHost}:${httpsPort}`);
});

Step 5: Create an HTML File

Create an index.html file in the src directory with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image Grid</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
      background-color: #f0f0f0;
    }
    .grid-container {
      display: grid;
      grid-template-columns: repeat(5, 1fr);
      gap: 10px;
      width: 100%;
      height: 100%;
      padding: 10px;
      box-sizing: border-box;
    }
    .grid-item {
      position: relative;
      width: 100%;
      padding-top: 5%;
      overflow: hidden;
    }
    .grid-item img {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 100%;
      height: 100%;
      object-fit: cover;
      transform: translate(-50%, -50%);
    }
  </style>
</head>
<body>
  <div class="grid-container">
    <div class="grid-item"><img src="/cars/1.jpg" alt="Image 1"></div>
    <div class="grid-item"><img src="/cars/2.jpg" alt="Image 2"></div>
    <div class="grid-item"><img src="/cars/3.jpg" alt="Image 3"></div>
    <div class="grid-item"><img src="/cars/4.jpg" alt="Image 4"></div>
    <div class="grid-item"><img src="/cars/5.jpg" alt="Image 5"></div>
    <div class="grid-item"><img src="/cars/6.jpg" alt="Image 6"></div>
    <div class="grid-item"><img src="/cars/7.jpg" alt="Image 7"></div>
    <div class="grid-item"><img src="/cars/8.jpg" alt="Image 8"></div>
    <div class="grid-item"><img src="/cars/9.jpg" alt="Image 9"></div>
    <div class="grid-item"><img src="/cars/10.jpg" alt="Image 10"></div>
  </div>
</body>
</html>

Explanation of the HTTPS Server Code

  1. Import Required Modules:
    • We import necessary modules such as createServer from node:https, createReadStream, readFileSync from node:fs, extname, resolve from node:path, and mime from mime-types.
    • The zlib module is used for compressing the responses.
  2. Define Brotli Options:
    • We define Brotli compression options to enhance performance.
  3. Set Server Port and Host:
    • We specify the port and host where the server will listen.
  4. SSL Options:
    • SSL options including the key and certificate are read from the ssl directory.
  5. Create the HTTPS Server:
    • We create the HTTPS server using the createServer method.
    • If the request URL is /, the server responds with the content of index.html.
    • For other URLs, the server tries to serve the requested file. The response is compressed using Brotli.
  6. Start the Server:
    • The server listens on the specified port and host, and logs a message when it’s up and running.

Step 6: Run the Server

To start the server, run:

node src/server/http1.js

You should see a message indicating that the server is running. Open your browser and navigate to https://localhost:8080 to see the server in action. Note that you’ll need to accept the self-signed certificate.

Next steps

Now that you’ve successfully set up and tested an HTTPS 1.1 server, you can proceed to set up an HTTP/2 server with Node.js. Follow the detailed guide here: Setting Up and Testing an HTTP/2 Server with Node.js