案例体验HTTP2.0多路复用

2,080 阅读4分钟

大家好,我是小鑫同学。一位长期从事前端开发的编程爱好者,我信奉编程最重要的是分享。请跟随小鑫同学的步伐,一起带你畅游不一样的前端世界~

HTTP协议经历了20多年的演进在2018年来到了HTTP3.0的时代,到现在时间HTTP2.0已经在大多数的主流站点得到了广泛的使用,可是你的网站升级到2.0版本了吗?今天就通过示例来演示如何从1.1版本升级到2.0版本,体验一下2.0版本的多路复用究竟能不能优化现有的站点呢?

1. 使用NodeJs实现HTTP2.0

在下面的网页中包含了24张图片,在HTTP1.1版本的时候受浏览器限制,同一域名同时发起的请求数量将限制在6~8次。在HTTP2.0采用多路复用替换的原来的机制,相同域名也只占用同一个TCP链接完成数据交换。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HTTP、HTTP2</title>
  </head>
  <body>
    <img width="30%" height="20%" src="images/1e2b54c596f813e44138769b2e76f169.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/5dce78ea79845fcf2f1b62dbf3acf620.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/7ad706b7e6e0442cea9d4e0347cd487d.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/9d90986693450e14afe74db3a05e336a.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/46f3da0e924a0b798bfe461759b8779c.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/47d28a384c0aefea2d4152a7805a132a.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/75c804f11e2f9b3d3ad9adf6f143ac22.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/94bddbdc4d93fcf58b9e46b3feabee8e.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/500e4caf9a5b392fac176bc8dae8fb40.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/86627adf5e44df12be9e7ee436b6a28d.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/ae8e846f6fd915c67e26ab59fb1bf655.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/c22e0ae61c5759134c46ef1a63fc746e.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/c45b5212ef77b3f9b16660faef173517.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/c540e2e5a1aa4209c92ab9a4a7e3018d.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/c5734d100410e544e91edbcb7608d8bc.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/cde25fb6bd5df4ff66930faece0779f5.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/cfc76fef4149c84ee6bb82a251171f60.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/d383e4bd00949edf2b301ffb7585e8aa.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/e240d3b230d4fe71f9ef64e0bf855c3b.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/e528b014d2c0a4b69b5e58c61bfe47e7.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/f917bfe3a042f91b4213d53b383ca1fa.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/08e5d3f7c7d9e46bf0072f3296147f55.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/887a346047f75aca61108f06f07de9cc.jpeg" alt="" srcset="" />
    <img width="30%" height="20%" src="images/3e12a1db86d48b881acbc2b7d24d995e.jpeg" alt="" srcset="" />
  </body>
</html>

1.1 编写HTTP1.1版本案例:

在NodeJs中http包默认使用的就是HTTP1.1版本协议,通过createServer函数实现默认和图片访问的两种响应方式:

import http from "node:http";
import fs from "node:fs";
import cp from "node:child_process";

const server = http.createServer((req, res) => {
  const url = req.url;
  if (url === "/") {
    const html = fs.readFileSync("index.html");
    res.writeHead(200, {
      "content-type": "text/html; charset=utf-8",
    });
    res.write(html);
    res.end();
  } else if (url?.startsWith("/images/")) {
    const img = fs.readFileSync(`.${url}`);
    res.writeHead(200, {
      "content-type": "image/*",
    });
    res.write(img);
    res.end();
  }
});

server.listen(8553, () => {
  console.log("> HTTP服务启动成功");
  cp.exec("start http://localhost:8553");
});

注:使用child_process模块在服务启动后自动打开默认浏览器并跳转到http://localhost:8553

1.2 编写HTTP2.0版本案例:

在使用HTTP2.0版本时需要同时支持HTTPS安全协议,我们就需要生成一份自签名证书,生成自签名证书可以使用mkcert开源项目:

# install mkcert from scoop
scoop bucket add extras
scoop install mkcert

注:安装时请注意要科学一点;

HTTP2.0版本协议在NodeJs中的http2模块中得到支持,使用时请注意NodeJs版本,我们在体验一些功能时做好切换NodeJs到较高的版本;

使用NodeJs中的http2模块实现案例,支持默认和图片访问的两种响应方式:

import http2 from "node:http2";
import fs from "node:fs";
import cp from "node:child_process";

// 配置自签名证书
const server = http2.createSecureServer({
  key: fs.readFileSync("./keys/localhost-key.pem"),
  cert: fs.readFileSync("./keys/localhost.pem"),
});

server.on("error", (err) => console.log(err));

server.on("stream", (stream, headers) => {
  const path = headers[":path"];
  if (path === "/") {
    const html = fs.readFileSync("index.html");
    stream.respond({
      "content-type": "text/html; charset=utf-8",
      ":status": 200,
    });
    stream.write(html);
    stream.end();
  } else if (path?.startsWith("/images/")) {
    const img = fs.readFileSync(`.${path}`);
    stream.respond({
      "content-type": "image/*",
      ":status": 200,
    });
    stream.write(img);
    stream.end();
  }
});

server.listen(8443, () => {
  console.log("> HTTP2服务启动成功");
  cp.exec("start https://localhost:8443");
});

1.3 添加脚本并启动案例:

1.3.1 添加两个版本的启动脚本:

{
  "scripts": {
    "http": "npx esno ./server-http.ts",
    "http2": "npx esno ./server-http2.ts"
  }
}

1.3.2 开启版本协议查看:

使用Chrome浏览器通过NetWork来观察网络请求情况时默认不支持协议版本的查看,或者查看不方便,这里可以启用一下:

1.3.3 调整浏览器网络请求速度:

在浏览器中调整网速来模拟慢网络下数据加载,方便观察请求的访问情况;

1.3.4 查看HTTP1.1下网络请求数限制:

在1.1版本中很明显看到网络在分批加载并且后续的网络需要等待前面网络请求完成后开始;

1.3.5 查看HTTP2.0下网络请求同时进行:

在2.0版本中看到几乎所有的请求都在同一时间发起,充分利用网络带宽的优势来同服务器进行数据的交换;

2. 为Nginx开启HTTP2.0:

Nginx版本和OpenSSL版本都有一定的要求,在实战使用时请注意版本问题,目前我在Win本上使用的Nginx版本是1.22.1,OpenSSL版本是1.1.1k 25 Mar 2021

nginx                                           
├─ conf                                         
│  ├─ ...                              
│  └─ nginx.conf                                   
├─ html                                         
│  ├─ images                                    
│  │  ├─ ...  
│  │  └─ f917bfe3a042f91b4213d53b383ca1fa.jpeg  
│  └─ index.html                                                             
└─ nginx.exe                                    

2.1 配置默认HTTP1.1版本:

server {
    listen       80;
    server_name  localhost;

    location / {
        root   html;
        index  index.html index.htm;
    }

    location /images/* {
        root   html;
    }
}

2.2 配置HTTP2.0版本和自签名证书:

server {
    listen 443 ssl http2;
    server_name  localhost;

    ssl_certificate ../../keys/localhost.pem;
    ssl_certificate_key ../../keys/localhost-key.pem;

    location / {
        root   html;
        index  index.html index.htm;
    }

    location /images/* {
        root   html;
    }
}

在启动Nginx服务后,重新观察http://localhost/https://localhost/在NetWork请求情况可以得到了NodeJs版本相同的结果;

3. HTTP1.1 PK HTTP2.0

3.1 请求数据包体积:

开启HTTP2.0请求资源的数据包远小于HTTP1.1版本:

HTTP2.0

HTTP1.1

3.2 连接数量:

开启HTTP2.0的请求公用了同一个连接来交换数据,而HTTP1.1则建立了6个连接交换数据,一定程度减少了服务器连接数剧增的压力:

HTTP2.0连接数1

HTTP1.1连接数6

4. 已升级HTTP2.0版本网站:

4.1 百度图片搜索:

4.2 微博主页:

4.3. 今天头条主页:

4.4 稀土掘金主页:

4.5 InfoQ主页:

总结

通过案例对比似乎发现HTTP2.0版本的协议似乎并没有启到什么效果,但是网络的优化也需要方方面面的考虑,在主流网站几乎全部支持了HTTP2.0时候我觉得有必要考虑将自己还没有升级2.0的网站提上日程。

更好的体验HTTP2优势的案例参照:http2.akamai.com/demo

先简单的补充一下通过抓包观察到的截图,有更好的验证方式欢迎指导,比如是否可以通过压力测试来验证呢?

本文项目已推送至GitHub,欢迎克隆演示:git clone git@github.com:OSpoon/awesome-examples.git


如果看完觉得有收获,欢迎点赞、评论、分享支持一下。你的支持和肯定,是我坚持写作的动力~

最后可以关注我@小鑫同学。欢迎点此扫码加我微信fe-xiaoxin交流,共同进步(还可以帮你fix🐛)~

本文正在参加「金石计划 . 瓜分6万现金大奖」