作者 | wanago 译者 | 小大非 编辑 | Yonie

HTTP 协议于 1991 年引入,至今已有近 30 年的历史。自第一个文档化版本 (后来称为 0.9) 以来,它已经经历了一段相当长的历程。在本文中,我们将简要回顾 HTTP 协议的发展历史,重点介绍 HTTP/2 带来了什么,以及我们如何从中获益。我们将使用 Node.js 服务端来实现它。

HTTP 协议简史

HTTP 的第一个版本只能传输超文本标记语言 (HTML) 文件,因此我们称之为超文本传输协议。它真的很简单,唯一可用的方法就是 GET。它没有 HTTP 头文件或状态代码。如果出现问题,服务器可以使用带有错误描述的 HTML 文件进行响应。

1996 年 1.0 版本出现了。与前一个版本相比,它进行了许多改进,其中最重要的是状态代码、POST 和 header 等附加方法。现在,我们可以使用 Content-Type 头来传输普通 HTML 之外的文件。

1997 年发布的 HTTP/1.1 引入了一些其它的改进。除了添加像 OPTIONS 这样的方法外,它还引入了 Keep-Alive 头。它允许一个连接对多个 HTTP 请求保持打开状态。因为这点,连接不必在每次请求之后关闭,然后再重新打开。在 HTTP/1.1 中,我们通常一次只能有 6 个连接。例如,如果其中一个请求由于服务器上的某些复杂逻辑而卡住,那么它们中的每一个都可以一次处理一个请求,整个连接就会冻结并等待响应。这个问题称为前端阻塞。

实现 Node.js HTTP/2 的好处

堆栈中有很多实现 HTTP/2 的方法。一种常见的方法可能是在 web 服务器上实现它,但是在本文中,我们在应用程序层中实现它,以便拓展 Node.js 的相关知识。因为浏览器不支持未加密的 HTTP/2,这意味着我们需要通过 HTTPS 协议实现 TLS 连接。要在本地完成此操作,我们使用以下命令生成证书:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out certificate.pem -days 365 -nodes

如果你想了解详细信息,请查看 《使用 OpenSSL 证书实现 HTTPS》,相关链接为: https://wanago.io/2019/04/01/node-js-typescript-8-implementing-https-with-our-own-openssl-certificate/

import * as http2 from 'http2';import * as fs from 'fs';import * as util from 'util';

const readFile = util.promisify(fs.readFile);

async function startServer() {  const [key, cert] = await Promise.all([    readFile('key.pem'),    readFile('certificate.pem')  ]);

  const server = http2.createSecureServer({ key, cert })    .listen(8080, () => {      console.log('Server started');    });

  server.on('stream', (stream, headers) => {    stream.respond({      'content-type': 'text/html',      ':status': 200    });    stream.end('

Hello World

');
});

server.on('error', (err) => console.error(err));
}

startServer();
解决某些复杂应用程序中的前端阻塞问题

即使使用 HTTP/1.1 进行 6 个并行连接也可能不够用,尤其是当我们遇到前端阻塞时。HTTP/2 通过允许一个连接同时处理多个请求解决了这个问题,这是因为即使其中一个请求被卡住,其它的请求也可以继续。在上面的这个简单示例中,我们使用普通 HTML 进行响应。每当有人向我们的服务器发出请求时,流事件就会触发。

如果你想了解更多关于流的信息,请查看 《可读流的暂停和流动模式》 和 《可写流、管道和流程流》,相关链接为:

《可读流的暂停和流动模式》: https://wanago.io/2019/03/04/node-js-typescript-4-paused-and-flowing-modes-of-a-readable-stream/

《可写流、管道和流程流》: https://wanago.io/2019/03/11/node-js-typescript-5-writable-streams-pipes-and-the-process-streams/

在 headers 参数中,我们有即将到来的请求的所有 header。它是一种检查方法,比如请求的方法和路径。现在,由于我们使用 HTTP/2,浏览器使用一个非阻塞的连接。一个可以关注的例子是 Golang 团队创建的一个网格演示(详情请见下方链接)。在使用 HTTP/2 时,由于在同一连接上处理并行请求和处理前端阻塞问题,你可以看到性能的显著提高。

相关链接:

Golang 团队的网格演示: https://http2.golang.org/gophertiles

报头压缩

HTTP/2 使用了一种新的报头压缩算法,我们称之为 HPACK。一些参与定义 HTTP/2 协议的开发人员也在开发 SPDY,它以前也用于压缩报头。不幸的是,后来人们发现它容易受到 CRIME 攻击。HPACK 不仅使整个过程更加安全,而且在某些情况下速度更快。

使用服务端推送缓存数据

当我们实现 HTTP/2 时,上面所有的改进都是开箱即用的。这并不是它全部的能力。通过服务器推送,我们现在可以在客户机缓存中填充数据。我们甚至可以在浏览器请求之前完成。一个基本的使用场景是当用户请求 index.html 文件时的情况。

server.on('stream', (stream, headers) => {  const path = headers[":path"];  switch(path) {    case '/': {      stream.respond({        'content-type': 'text/html',        ':status': 200      });      stream.end(`

Hello World

`);
break;
}
case '/style.css': {
stream.respond({
'content-type': 'text/css',
':status': 200
});
stream.end(`
body {
color: red;
}
`);
break;
}
default: {
stream.respond({
':status': 404
});
stream.end();
}
}
});

在上面的示例中,当用户访问主页时,它请求 index.html 文件。当它得到一个样式表时,它会注意到还需要 style.css 文件。在请求 index.html 和 style.css 之间有一些延迟,我们可以使用服务端推送来处理它。因为我们知道用户将需要 style.css 文件,所以可以将它与 index.html 一起发送。

server.on('stream', (stream, headers) => {  const path = headers[":path"];  switch(path) {    case '/': {      stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {        if (err) throw err;        pushStream.respond({          'content-type': 'text/css',          ':status': 200        });        pushStream.end(`          body {            color: red;          }        `);      });      stream.respond({        'content-type': 'text/html',        ':status': 200      });      stream.end(`

Hello World

`);
break;
}
case '/style.css': {
stream.respond({
'content-type': 'text/css',
':status': 200
});
stream.end(`
body {
color: red;
}
`);
break;
}
default: {
stream.respond({
':status': 404
});
stream.end();
}
}
});

现在使用 stream.pushStream 只要有人请求 index.html,我们就发送 style.css 文件。当浏览器处理它时,它会看到标记,并注意到它还需要 style.css 文件。由于服务端推送,它已经缓存在浏览器中,因此不需要发送另一个请求。

总结

HTTP/2 旨在通过满足日益复杂的 web 页面的需求来提高性能。我们使用 HTTP 协议发送的数据量增加了,HTTP/2 通过处理前端阻塞等方法解决了这个问题。另外由于在同一连接上处理并行请求,这也解除了 HTTP/1.1 的一些限制。

英文原文: https://wanago.io/2019/07/15/node-js-typescript-benefits-http2-protocol/

http body 二进制流_HTTP/2协议的优点解析相关推荐

  1. springmvc使用谷歌captcha生成图片验证码,并将验证码图片以二进制流的方式返回给前端(app和pc端都能调用)

    近期对登录注册与获取短信验证码的接口做了安全限制,其中一部分就用到了谷歌的captcha验证码,比如当用户连续三次登陆失败,那么之后的登录请求就需要用户输入谷歌的图形验证码.由于web端和app端调用 ...

  2. [.net 面向对象程序设计进阶] (9) 序列化(Serialization) (一) 二进制流序列化

    [.net 面向对象程序设计进阶]  (9)  序列化(Serialization) (一) 二进制流序列化 本节导读: 在.NET编程中,经常面向对象处理完以后要转换成另一种格式传输或存储,这种将对 ...

  3. tcp是流式传输协议-tcpdump抓包印证

    结论: 1. tcp 是流式传输协议,"流(stream)"的 含义 像河流 一样,包和包之间紧紧相互挨着,内核协议栈(tcp)不会使用特殊分隔符分割,实质上它也根本不关心这些流里 ...

  4. 将二进制流转换为图片

    如何从数据库中取出blob类型数据,并且转换为图片存到固定的路径 首先从数据库里面讲blob类型的数据取出来: byte[] photo = userinfo.getPhoto();String pa ...

  5. python把文件读成字节流_Python中对字节流/二进制流的操作:struct

    前言 前段时间使用Python解析IDX文件格式的MNIST数据集,需要对二进制文件进行读取操作,其中我使用的是struct模块.查了网上挺多教程都写的挺好的,不过对新手不是很友好,所以我重新整理了一 ...

  6. iOS 二进制流转化-项目笔记

    自己在做一个项目时,需要使用socket通信,要和java中bytebuffer转换的属性一样,需要将所有的类型如:int,short,long,string类型转成和java或者c++通信都使用的二 ...

  7. http传输html图片方式,http怎么样传输图片?二进制流还是base64编码

    面试官问本人http怎么传图片的,本人说二进制流  但他说图片是通过base64编码后传的 本人只是知道这种方法也可行 当时本人也不好得跟他争辩 回来后本人抓包分析后 觉得他说的有问题 .下面是本人用 ...

  8. php pack、unpack、ord 函数使用方法(二进制流接口应用实例)

    park,unpark,ord这3个函数,在我们工作中,用到它们的估计不多. 我在最近一个工作中,因为通讯需要用到二进制流,然后接口用php接收.当时在处理时候,查阅不少资料.因为它们使用确实比较少, ...

  9. 前端将二进制数据流转为文件_前端通过二进制流下载文件

    JS下载文件两种方式总结: 下载文件主要分为两种形式,具体使用哪种方式取决于后台: 1.如果后台服务器的静态目录有可供下载的静态资源,后台接口返回文件路径,直接window.location.href ...

最新文章

  1. 刻意练习:LeetCode实战 -- 二叉树的前序遍历
  2. gateway 内存溢出问题_带你学习jvm java虚拟机 arthas/性能调优/故障排除/gc回收/内存溢出等...
  3. 用什么擦地最干净脑筋急转弯_脑筋急转弯:手机的反义词是什么?答案让人笑得肚子疼!...
  4. RxSwift之深入解析URLSession的数据请求和数据处理
  5. 六种排序算法的JavaScript实现以及总结
  6. web自动化如何在不同浏览器运行_自动化决策环节的“心脏”将如何与众不同?...
  7. html视频标签不显示,HTML视频标签无法正确显示视频
  8. 不花钱、不买服务器可以搭建个人博客吗?快进来,给你安排!
  9. 沪教版神奇的机器人分段_神奇的机器人课文教学设计
  10. perl lwp 超时问题
  11. 使用@Conditional条件注解
  12. 【Scratch画图100例】图40-scratch实心五角星 少儿编程 scratch编程画图案例教程 考级比赛画图集训案例
  13. 【机器学习实战】1、机器学习主要任务
  14. 面试官:如何设计群聊消息的已读未读功能?
  15. 计算机在材料化学中的应用大纲,材料化学-《材料研究方法》课程教学大纲
  16. Mesa学习笔记#1:Running MESA
  17. 一个简单的自定义alert方法
  18. 什么是主从复制?mysql主从复制?redis主从复制?
  19. Oracle提示TNS:无监听程序的解决办法
  20. 硕士论文参考文献编号排版

热门文章

  1. 软件测试-验收测试与回归测试
  2. HTML5 Geolocation用来定位用户的位置。
  3. vue 项目中当访问路由不存在的时候默认访问404页面
  4. Jumpserver跳板机
  5. thinkphp3.2+cropper上传多张图片剪切图片
  6. 畅通工程(自己写的BFS,但后面想了下并查集更好更快)
  7. 每天学一点ubuntu指令
  8. AngularJs编辑器
  9. SwipeRefreshLayout下拉刷新
  10. postgreSQL源码分析——索引的建立与使用——Hash索引(3)