The Evolution of HTTP and Why Companies Should Move to HTTP2

·

11 min read

Why should we even care?

Let's say you are surfing through Instagram when you notice the advertisement "How to become a great engineer." "Click to register for the free webinar." The page takes 20 seconds to load when you click on it. It is typically seen that users are more likely to lose interest in an advertisement if it takes too long for it to load, which lowers engagement and decreases conversion rates.

A study conducted by Google found that a delay of just one second in page load time can result in a 20% decrease in conversions.

AutoAnything is an online retailer that sells auto parts and accessories. They managed to increase their sales by 12–13% by reducing their page load times by 50%.

Amazon: In 2006, Amazon discovered that for every 100 ms improvement in their page load times, they experienced a 1% increase in revenue. They have continued to invest heavily in website speed and performance optimization ever since.

These examples demonstrate how website speed and performance can have a significant impact on a company's sales and revenue. And that’s why load time is very important.

History of HTTP

HTTP (Hypertext Transfer Protocol) is the foundation of the World Wide Web. It is a protocol that allows communication between web servers and web clients. HTTP has gone through several iterations since its inception in 1991, with the latest version being HTTP/2. We will discuss HTTP1, HTTP1.1, and HTTP2 in this article.

HTTP1 or HTTP1.0

HTTP 1.0, also known as the first version of HTTP, was released in 1996. It introduced several key features and improvements over its predecessor, HTTP 0.9.

  • Express NodeJS App

      const express = require('express');
      const app = express();
    
      app.get('/', (req, res) => {
        res.send('Hello, world!');
      });
    
      app.listen(3000, () => {
        console.log('Server listening on port 3000');
      });
    

Some of the main features of HTTP 1.0 include:

  1. Support for multiple protocols: HTTP 1.0 introduced support for multiple protocols, including TCP/IP, SSL/TLS, and MIME.

  2. Request methods: HTTP 1.0 allowed for the use of several request methods, including GET, POST, HEAD, and others. This allowed for more complex interactions between clients and servers.

  3. Support for headers: HTTP 1.0 added support for headers, which allowed for metadata to be included in HTTP requests and responses. This allowed for more flexibility and customization in the protocol.

  4. Basic authentication: HTTP 1.0 included support for basic authentication, which allowed for users to be authenticated using a simple username and password.

  5. Caching: HTTP 1.0 included basic support for caching, which allowed frequently requested content to be stored locally on the client or server for faster access.

Limitations

There were various limitations in HTTP 1, but one of the main limitations of HTTP 1.0 was the lack of support for persistent connections. In HTTP 1.0, a new TCP connection had to be established for each request/response pair. This meant that after the server had responded to a client request, the connection would be closed and a new one would have to be established for any subsequent requests.

This constant opening and closing of connections led to increased overhead and slower performance. The overhead came from the need to establish a new connection each time a request was made, which involved a three-way handshake process. Additionally, there was a delay in waiting for the server to open and close the connection, which added to the overall latency.

Web browsers addressed the limitation of persistent connections in HTTP 1.0 by implementing connection pooling. This involved keeping a pool of multiple connections open between the client and server, allowing multiple requests to be sent over each connection. Typically, web browsers limit the number of connections in the pool to around 6. With connection pooling, web pages could load faster and with less overhead. However, connection pooling was not as efficient as persistent connections in later versions of the HTTP protocol.

HTTP1.1

HTTP 1.1 introduced several new features and improvements over HTTP 1.0, including persistent connections, chunked encoding, request pipelining, and the "Host" header. These features improved the efficiency and performance of HTTP requests and enabled the development of more complex web applications. HTTP 1.1 also introduced support for range requests, which allow clients to request only a portion of a resource from the server. Overall, HTTP 1.1 was a significant improvement over HTTP 1.0.

  • Express NodeJs App

      const express = require('express');
      const app = express();
      const cors = require('cors');
    
      app.use(cors());
    
      // Set up keep-alive headers
      app.use((req, res, next) => {
        res.set('Connection', 'keep-alive');
        next();
      });
    
      // Define routes
      app.get('/users', (req, res) => {
        console.log(`New connection from ${req.connection.remoteAddress}:${req.connection.remotePort}`);
        const users = [
          { id: 1, name: 'Alice' },
          { id: 2, name: 'Bob' },
          { id: 3, name: 'Charlie' },
        ];
        res.json(users);
      });
    
      app.get('/products', (req, res) => {
        console.log(`New connection from ${req.connection.remoteAddress}:${req.connection.remotePort}`);
        const products = [
          { id: 1, name: 'Widget' },
          { id: 2, name: 'Gadget' },
          { id: 3, name: 'Thingamajig' },
        ];
        res.json(products);
      });
    
      // Start the server
      const port = 2323;
      app.listen(port, () => {
        console.log(`Server listening on port ${port}`);
      });
    

One study conducted by Google found that the average page load time on HTTP 1.1 was about 30% faster than on HTTP 1.0.

Limitation

HTTP/1.1 has limitations such as high latency, limited concurrency, head-of-line blocking, a lack of built-in encryption, and no server push. These limitations have been addressed in newer versions of the HTTP protocol, such as HTTP/2 and HTTP/3.

Now, before going to HTTP2 or H2, let's understand TLS.

TLS

TLS (Transport Layer Security) is a cryptographic protocol used to provide secure communication over the internet. TLS is used to encrypt the data transmitted between a web server and a web browser, ensuring that sensitive information, such as passwords, credit card details, and other personal information, is protected from eavesdropping, tampering, and forgery.

TLS is used in many applications where secure communication is important, such as e-commerce websites, online banking, email, and instant messaging. Any application that involves the transmission of sensitive information over the internet should use TLS to protect against unauthorized access and ensure data privacy.

In the context of an Express.js application, TLS can be implemented using the built-in https module, which allows you to create an HTTPS server using TLS. Here's an example of how to create an HTTPS server with Express.js and TLS:

  • Express App

      const https = require('https');
      const express = require('express');
      const fs = require('fs');
    
      const app = express();
    
      // Your Express.js routes here
      app.get('/', (_, res) => res.send('Hello from HTTPS world'));
    
      // You can use openssl or letsEncrypt to generate certificates
      // Create HTTPS server with TLS
      const options = {
        key: fs.readFileSync('path/to/private/key.pem'),
        cert: fs.readFileSync('path/to/certificate.pem')
      };
    
      https.createServer(options, app).listen(443, () => {
        console.log('HTTPS server running on port 443');
      });
    

Till now, what we have seen is that there will be a client (browser) and a server (express app). The communication between clients and servers is direct.

The best practice is that clients should not call the server directly; we should have some reverse proxy in front of the backend server. There are several benefits to having a reverse proxy in front of a backend Express app.

  1. Load balancing: A reverse proxy can distribute incoming requests across multiple backend servers, which helps to balance the load and improve the performance of the application.

  2. Security: A reverse proxy can act as a barrier between the internet and the backend server, which can help protect against security threats such as DDoS attacks and SQL injections. Additionally, a reverse proxy can be configured to block or filter certain requests based on specific criteria, such as IP address or user agent.

  3. Scalability: By using a reverse proxy, you can easily add or remove backend servers as needed to scale the application to handle increased traffic or workload.

  4. Caching: A reverse proxy can cache frequently requested content, which can improve the performance of the application by reducing the number of requests that need to be processed by the backend server.

  5. SSL termination: A reverse proxy can handle SSL/TLS termination, which offloads the encryption and decryption of HTTPS traffic from the backend server and improves performance.

Now the question is, where should we add TLS?

  • At the NGINX level

  • at the Express level.

TLS (Transport Layer Security) should be enabled at the reverse proxy level (e.g., Nginx) rather than at the Express app level. This is because the reverse proxy is the entry point for incoming requests from the internet, and it's responsible for handling SSL/TLS termination and forwarding decrypted requests to the backend application server (e.g., Express app) over an unencrypted connection.

By enabling TLS at the reverse proxy level, you can centralize the configuration and management of SSL and TLS certificates and reduce the load on the application server. Additionally, you can offload SSL/TLS encryption and decryption tasks from the application server, which can improve performance and scalability.

In an Nginx setup, you can enable TLS by configuring the ssl_certificate and ssl_certificate_key directives with the path to your SSL/TLS certificate and private key files, respectively. You can also configure other SSL/TLS settings, such as the SSL/TLS protocol version and cipher suite, to ensure the highest level of security and compatibility with modern web browsers.

Once TLS is enabled at the reverse proxy level, you can configure your Express app to use regular HTTP instead of HTTPS, as the incoming requests are already decrypted and forwarded by Nginx over an unencrypted connection. However, you should still ensure that your Express app is configured to use secure cookies and other security best practices to protect against attacks such as session hijacking and cross-site scripting (XSS).

  • Example of setting up reverse proxy with express app.

      // Create an express server app on PORT = 4040, assumping app is running fine.
    
      // Install nginx
      sudo apt update && sudo apt install nginx
    
      // check nginx status, nginx should run if not run **sudo systemctl start nginx**
      sudo systemctl status nginx
    
      // now we need ssl certificate, use certbot its free
      // install certbot
      sudo snap install --classic certbot && sudo ln -s /snap/bin/certbot /usr/bin/certbot
    
      // Assuming u have a domain name: dev.example.com, if not hop over to web service and add 1 record
      sudo certbot --nginx -d example.com
      // Above command will create a certificate and other files which can be located at /etc/letsencrypt/live/dev.example.com
      // also it wil update /etc/nginx/sites-available/default
    
      // Now we have to map nginx port 80 and 443 with our express app running on 4040
      // Update your nginx/sites-available/default file with this.
      **server {
          listen 80;
          listen [::]:80;
          listen 443 default_server ssl;
    
          server_name dev.example.com;
    
              # Update the path to urs if needed
          ssl_certificate /etc/letsencrypt/live/dev.example.com/fullchain.pem; # managed by Certbot
          ssl_certificate_key /etc/letsencrypt/live/dev.example.com/privkey.pem; # managed by Certbot
          include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
          ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    
          location / {
              proxy_pass <http://localhost:4040/>;
          }
    
          if ($scheme = http) {
              return 301 https://$server_name$request_uri;
          }
      }**
    
      // Create symbolik link between sites-available and sites-enabled
      sudo ln -s /etc/nginx/sites-available /etc/nginx/sites-enabled
    
      //{Optional} Test ur nginx config file
      sudo nginx -t
    
      // Reload nginx config to work
      sudo nginx -s reload
    
      // Now we can test our website it should work
      curl -v <https://dev.example.com>
    

HTTP2

HTTP/2 is a new version of the HTTP protocol that was developed to improve the performance and efficiency of the web. It was released in May 2015 and is based on the SPDY protocol created by Google. HTTP/2 is designed to address some of the limitations of HTTP/1.1.

Functionality of HTTP/2 HTTP/2 provides several new features and improvements over HTTP/1.1, including:

  1. Multiplexing: HTTP/2 allows multiple requests to be sent and received over a single TCP connection, eliminating the need for multiple connections between the client and server. This reduces the overhead of establishing and maintaining connections, resulting in faster page load times.

  2. Server push: HTTP/2 allows servers to push resources to the client before they are requested. This can reduce the number of round trips between the client and server, resulting in faster page load times.

  3. Binary format: HTTP/2 uses a binary format instead of the text-based format used by HTTP/1.1. This reduces the overhead of parsing and processing the protocol, resulting in faster page load times.

  4. Header compression: HTTP/2 uses HPACK compression to compress header data, reducing the size of headers and improving performance.

const express = require('express');
const http2 = require('http2');
const fs = require('fs');
const path = require('path');
const http2Express = require('http2-express-bridge');
const cors = require('cors');

// Use the wrapper function that returns the application
const app = http2Express(express);

app.use(cors());
app.get('/', (_, res) => res.send('Hello World2'));
app.get('/api/status', (_, res) => res.json({ status: 200, name: 'JACK' }));

const options = {
  key: fs.readFileSync(path.join(__dirname, 'mycert/selfsigned.key')),
  cert: fs.readFileSync(path.join(__dirname, 'mycert/selfsigned.crt')),
  allowHTTP1: true,
};

const server = http2.createSecureServer(options, app);

server.listen(3000, console.log(`listening on port 3000`));

Advantages of HTTP/2 The advantages of HTTP/2 are many. Some of the most significant benefits include:

  1. Improved performance: HTTP/2 can significantly improve page load times by reducing the number of round trips required to load a page.

  2. Increased security: HTTP/2 requires the use of SSL/TLS encryption, which improves security by encrypting all data exchanged between the client and server.

  3. Better resource utilization: HTTP/2 can make better use of network resources by allowing multiple requests to be sent and received over a single connection.

  4. Enhanced user experience: Faster page load times and improved performance can lead to a better user experience, which can lead to increased engagement and conversions.

Limitations of HTTP/2 Despite its many advantages, HTTP/2 has a few limitations, including:

  1. Implementation complexity: HTTP/2 is more complex than HTTP/1.1, which can make it more difficult to implement.

  2. Compatibility issues: Some older browsers and servers may not support HTTP/2, which can lead to compatibility issues.

  3. Increased resource usage: While HTTP/2 can make better use of network resources, it can also increase resource usage on the server.

Who is using HTTP/2? Since its release, HTTP/2 has been adopted by many major web browsers and servers, including Google Chrome, Firefox, Safari, and Microsoft Edge. Many popular websites, such as Google, Facebook, and Twitter, have also adopted HTTP/2.

Market Capture of HTTP/2 According to W3Techs, as of April 2023, HTTP/2 was used by 47.3% of all websites. This represents a significant increase from just a few years ago, when HTTP/2 adoption was still in its early stages.

How fast is HTTP2?

In general, HTTP/2 can provide up to a 50% reduction in page load times compared to HTTP/1.1. However, this can vary depending on the specific circumstances. For example, on a high-latency network, HTTP/2's multiplexing and server push features can provide significant speed improvements, while on a low-latency network, the differences may be less noticeable.