透视HTTP协议
罗剑锋(Chrono)
奇虎360技术专家,Nginx/OpenResty开源项目贡献者
立即订阅
6077 人已学习
课程目录
已完结 44 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词|To Be a HTTP Hero
免费
破冰篇 (7讲)
01 | 时势与英雄:HTTP的前世今生
02 | HTTP是什么?HTTP又不是什么?
03 | HTTP世界全览(上):与HTTP相关的各种概念
04 | HTTP世界全览(下):与HTTP相关的各种协议
05 | 常说的“四层”和“七层”到底是什么?“五层”“六层”哪去了?
06 | 域名里有哪些门道?
07 | 自己动手,搭建HTTP实验环境
基础篇 (7讲)
08 | 键入网址再按下回车,后面究竟发生了什么?
09 | HTTP报文是什么样子的?
10 | 应该如何理解请求方法?
11 | 你能写出正确的网址吗?
12 | 响应状态码该怎么用?
13 | HTTP有哪些特点?
14 | HTTP有哪些优点?又有哪些缺点?
进阶篇 (8讲)
15 | 海纳百川:HTTP的实体数据
16 | 把大象装进冰箱:HTTP传输大文件的方法
17 | 排队也要讲效率:HTTP的连接管理
18 | 四通八达:HTTP的重定向和跳转
19 | 让我知道你是谁:HTTP的Cookie机制
20 | 生鲜速递:HTTP的缓存控制
21 | 良心中间商:HTTP的代理服务
22 | 冷链周转:HTTP的缓存代理
安全篇 (7讲)
23 | HTTPS是什么?SSL/TLS又是什么?
24 | 固若金汤的根本(上):对称加密与非对称加密
25 | 固若金汤的根本(下):数字签名与证书
26 | 信任始于握手:TLS1.2连接过程解析
27 | 更好更快的握手:TLS1.3特性解析
28 | 连接太慢该怎么办:HTTPS的优化
29 | 我应该迁移到HTTPS吗?
飞翔篇 (4讲)
30 | 时代之风(上):HTTP/2特性概览
31 | 时代之风(下):HTTP/2内核剖析
32 | 未来之路:HTTP/3展望
33 | 我应该迁移到HTTP/2吗?
探索篇 (5讲)
34 | Nginx:高性能的Web服务器
35 | OpenResty:更灵活的Web服务器
36 | WAF:保护我们的网络服务
37 | CDN:加速我们的网络服务
38 | WebSocket:沙盒里的TCP
总结篇 (2讲)
39 | HTTP性能优化面面观(上)
40 | HTTP性能优化面面观(下)
答疑篇 (2讲)
41 | Linux/Mac实验环境搭建与URI查询参数
42 | DHE/ECDHE算法的原理
结束语 (1讲)
结束语 | 做兴趣使然的Hero
透视HTTP协议
登录|注册

31 | 时代之风(下):HTTP/2内核剖析

Chrono 2019-08-07
今天我们继续上一讲的话题,深入 HTTP/2 协议的内部,看看它的实现细节。
这次实验环境的 URI 是“/31-1”,我用 Wireshark 把请求响应的过程抓包存了下来,文件放在 GitHub 的“wireshark”目录。今天我们就对照着抓包来实地讲解 HTTP/2 的头部压缩、二进制帧等特性。

连接前言

由于 HTTP/2“事实上”是基于 TLS,所以在正式收发数据之前,会有 TCP 握手和 TLS 握手,这两个步骤相信你一定已经很熟悉了,所以这里就略过去不再细说。
TLS 握手成功之后,客户端必须要发送一个“连接前言”(connection preface),用来确认建立 HTTP/2 连接。
这个“连接前言”是标准的 HTTP/1 请求报文,使用纯文本的 ASCII 码格式,请求方法是特别注册的一个关键字“PRI”,全文只有 24 个字节:
PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
在 Wireshark 里,HTTP/2 的“连接前言”被称为“Magic”,意思就是“不可知的魔法”。
所以,就不要问“为什么会是这样”了,只要服务器收到这个“有魔力的字符串”,就知道客户端在 TLS 上想要的是 HTTP/2 协议,而不是其他别的协议,后面就会都使用 HTTP/2 的数据格式。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《透视HTTP协议》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(20)

  • 何用
    HTTP/2 底层还是依赖 TCP 传输,没有解决队头阻塞的问题啊,这就是为何 HTTP/3 要基于 UDP 来传输

    作者回复: 对,虽然是部分解决,但对于http/1来说已经是一个很大的进步了。

    2019-08-07
    3
  • 何用
    服务端是不是要为每一个客户端都单独维护一份索引表?连接的客户端多了的话内存不就OOM了嘛

    作者回复: 是的,不过动态表也有淘汰机制,服务器可以自己定制策略,不会过度占用内存。

    2019-08-07
    3
  • -W.LI-
    1.还是无状态,流状态只是表示流是否建立,单次请求响应的状态。并非会话级的状态保持
    2.小帧好,少量多次,万一拥堵重复的的少。假设大帧好,只要分流不用分帧了。
    3.每一个请求响应都是一个流,流和流之间可以并行,流内的帧还是有序串行。

    作者回复: good。

    2019-08-07
    3
  • 想个昵称好难
    还有一个问题想请教下老师,您之前在《HTTP的前世今生》上有一段回复是说,只要是HTTP/1.1,就都是文本格式,虽然里面的数据可能是二进制,但分隔符还是文本,这些都会 在“进阶篇”里讲, 不过我看到现在还是有点迷惑,所二进制协议和文本协议的区别是什么呢?可以按照stackoverflow中https://stackoverflow.com/questions/2645009/binary-protocols-v-text-protocols 的回答来理解吗?

    作者回复: 指的是协议本身的数据格式,而不是负载(payload)的格式。

    你看http/1,请求行、头、body里的分隔符,都是ASCII码。

    而http/2,是二进制帧,用字节、位来表示信息,没有ASCII码。

    你可以把自己想象成协议的解析器,你看到的协议头是什么格式,文本还是二进制。

    2019-08-07
    2
  • 想个昵称好难
    老师您好,打扰您实在是抱歉,想请教您一个问题,您在文中说HTTP/2会在两端维护“Key-Value”的索引表,静态表应该是一摸一样的,那动态表俩边一样吗?如果一样的话,同步是比较难做的事情吧,我看RFC文档中是这么写的,”When used for bidirectional communication, such as in HTTP, the encoding and decoding dynamic tables maintained by an endpoint are completely independent, i.e., the request and response dynamic tables are separate.“, 所以我的理解是,动态表在客户端和服务器各自都有俩个表,一个是用来保存客户端发送的message的header,另外一个是保存服务器发送的header, 我看stackoverflow中也是这么写的,https://stackoverflow.com/questions/53003333/how-does-headers-keep-sync-in-both-client-and-server-side-in-http-2, 如果我有哪个地方理解错了,麻烦下老师指点一下

    作者回复: 是的,客户端和服务器维护各自的动态表,收发各一张表,但字典里的内容必须是一致的,否则索引号就对不上了。

    2019-08-07
    2
  • 许童童
    HTTP/2 的动态表维护、流状态转换很复杂,你认为 HTTP/2 还是“无状态”的吗?
    还是无状态的,对上层应用来说,动态表维护、流状态转换这些操作对它不可见。

    HTTP/2 的帧最大可以达到 16M,你觉得大帧好还是小帧好?
    大帧好,应该小帧需要很多额外的头信息,有数据冗余。小帧可以当出差错时,只转输出错的帧,细粒度控制。

    结合这两讲,谈谈 HTTP/2 是如何解决“队头阻塞”问题的。
    因为流可以并发,一个流被阻塞了,并不影响其它的流。

    作者回复: 我个人认为小帧比较好,当然如果在某些特定场景里,比如下载大文件,可以适当加大。

    2019-08-07
    1
    2
  • Geek_54edc1
    3、首先要明确造成“队头阻塞”的原因,因为http1里的请求和应答是没有序号标识的,导致了无法将乱序的请求和应答关联起来,也就是必须等待起始请求的应答先返回,则后续请求的应答都会延迟,这就是“队头阻塞”,而http2采用了虚拟的“流”,每次的请求应答都会分配同一个流id,而同一个流id里的帧又都是有序的,这样根据流id就可以标识出同一次的请求应答,不用再等待起始请求的应答先返回了,解决了“队头阻塞”

    作者回复: http/1里的请求都是排队处理的,所以有队头阻塞。

    http/2的请求是乱序的,彼此不依赖,所以没有队头阻塞。

    2019-08-07
    2
  • sunxu
    想问一下,nginx前端采用http2, 反向代理到应用服务使用的http1.1, 这种方式对请求响应有提升吗?

    作者回复: Nginx作为代理,实际上就把传输链路拆分成了两个部分,下游因为使用了http/2,所以肯定会有性能提升。

    而上游还是http/1,所以瓶颈就在这里,但因为后台系统的服务能力都很强,网络也好,所以不会有太大影响。

    当然,如果全用http/2就更好了。

    2019-08-07
    2
  • 许童童
    老师你好,nginx反向代理与服务端应用间有必要使用HTTP2吗?对性能提升大吗?

    作者回复: 如果有可能就尽量用http/2,HPack、流都可以提升性能,具体能提升多少就要看应用场景了,需要做测试。

    2019-08-07
    1
  • Geek_54edc1
    1、http的“无状态”是指对事务处理没有记忆,每个请求之间都是独立的,这与HPACK算法里的动态表、流状态转换是两回事。HPACK算法里维护动态表是用于头部压缩,而流状态转换只是表示一次请求应答里流的状态,都不会记录之前事务的信息

    作者回复: 说的很好,也可以这么表述“语法上有状态,语义上无状态”。

    2019-08-07
    1
  • -W.LI-
    老师好!TCP网络不好的时候会降速,http2的话是一个帧没收到就会导致TCP降速么?

    作者回复: 是的,会发生tcp层的队头阻塞,下一次http/3会讲。

    2019-08-07
    1
  • 张智凯
    1 http的无状态是针对应用层的吧,多个请求之前不会有影响,http2虽然有维护一些状态的信息,但这是针对流的信息,所以我认为http2也还是无状态的
    2 不知道大小帧哪个好,大帧头部占比会少一点,但在TCP层会需要拆分成小帧,可能会多耗点时间,太大的帧TCP发送缓存区也要设的大一点吧
    3 http2相比http1.1有了流ID来标识请求响应,因此同一个连接就可以同时进行多个流的传输,但由于TCP的收发窗口的确认机制,并发性还是会受到限制。

    总结:
    http2连接的建立
    建立完成TLS连接之后,发送连接前言PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n,这样后面的报文就会使用http2的格式
    报文格式:
    帧长度 3byte 默认上限为16k 最大为2^24
    帧类型 1byte 大致分为数据帧和控制帧,最高可表示256种,可自己扩展
    标志位 1byte 携带简单的控制信息
    流ID 4byte 其中最高位为0,客户端发起的流id为奇数,服务器发起的流id为偶数,0号流为控制流

    请求头字段采用HPACK的方式来进行压缩,有静态表来存储二元组(字段 ,value)和index之间的关系,静态表里找不到的key value,可以放在动态表里。

    作者回复: 总结的不错。

    1.可以说是语义无状态,语法有状态。

    2.通常都认为较小的帧比较好,粒度小,流的并行度就高。

    3.http/2在tcp层有队头阻塞,所以就出了http/3。

    2019-11-04
  • - shadow -
    老师你好,http2的头字段都是要求小写的,那服务端要升级到支持http2岂不是很难?因为很多头字段都是定义在程序里,我记得首字母是大写

    作者回复: 这个你不用担心,下层的程序会自动做处理。

    当然,现在我们应该都尽量小写字段名。

    2019-10-23
  • Geek_49a9e9
    为啥我打开31-1的pcap文件 看不到老师截图里面的抓包内容 只有TCP的报文

    作者回复: http/2采用是的加密通信,不解密是看不了的,需要在wireshark里指定SSLKEYLOGFILE,可参考“安全篇”。

    只要指定了对应的log文件,例如31-1.log,就能看到明文了。

    2019-09-11
  • Luke
    1、一个流中的多个帧是有序的,但是在二进制帧协议中,并没有看到这个序号,请问下老师,这个序号是在哪里?或者一个流中的多个帧是如何保证有序的?
    2、如果出现丢帧的情况是如何重传的?

    作者回复:
    1.由tcp保证帧是顺序到达的,因为tcp是有序的字节流。

    2.同样是由tcp实现,具体细节就太底层了,有兴趣可以研究tcp协议。

    2019-09-02
  • 闫飞
    哈夫曼编码的使用是HTTP2协议里面一个不容忽视的要素,该编码方式很好地保证了所有信息的平均码长最短而互相不构成前缀关系,易于解码。

    作者回复: great。

    2019-08-14
  • 信信
    上次留言说:课程里的所有链接都返回200,和访问http://www.chrono.com/一个效果,是一个由众多js,css组成的网站。。。
    作者: 建议打开开发者工具,看看uri是如何处理的。

    比如http://www.chrono.com/18-1?dst=/15-1?name=a.json,应该是跳转到15-1。

    有用开发者工具,显示的状态码就是200,并未跳转到15-1。。。。

    作者回复: 我在自己的实验环境又试了一下uri“http://www.chrono.com/18-1?dst=/15-1?name=a.json”

    会跳转,而且是两个请求,304和200。你的请求是访问的本地OpenResty吗?

    这里回复说不清楚,可以去GitHub上提issue。

    2019-08-08
  • sunözil
    老师 ,想请教一下,作为一个软件开发商,只交付系统不涉及硬件。需要在哪些方面保障系统安全性?

    作者回复: 这个话题有点大,单就Web服务来说,应该上https,然后加上waf安全防护,其他的还有防火墙、访问控制、身份认证、备份、审计什么的。

    2019-08-08
  • Geek_54edc1
    2、小帧好,如果多个流的帧可以在同一个tcp数据段发送的话,就可以提高网络利用率

    作者回复: great。

    2019-08-07
  • 我行我素
    请求复用。拆分传输,一个请求头被阻塞,不会影响其他请求

    作者回复: √

    2019-08-07
收起评论
20
返回
顶部