这里简单的介绍一下HTTP 2.0。
由HTTP 1.1 走向 HTTP 2.0
写这篇文章的时候我在听B站UP主翻唱的歌曲,然后我心血来潮打算看看B站现在用的是HTTP的哪个版本,于是我摁下了F12键。
这个h2和h3代表的是HTTP 2.0 和3.0? 这版本号刷的这么快的吗? 不应该是2.1==>2.5 ==>3.0这样吗?为了验证我的想法,我打开了火狐浏览器。
所以就很突然,本来按照计划只介绍HTTP/2.0的,然后HTTP/3.0也只得加入到学习计划中,所以每次学习一个知识点的时候,总会碰到新的,生也有涯,知也无涯的感觉,在前面两篇文章了,我们已经大致的介绍HTTP 0.9 、1.0、1.1。
2.0 与1.1的不同
1.1 的新特性
我们这里来再度介绍一下HTTP 1.1带来的改进:
- 连接可以复用,节省了多次打开 TCP 连接加载网页文档资源的时间。
HTTP 1.1 之前的连接模型使短连接,也是HTTP/1.0是短连接,每一个HTTP请求都由它自己独立的连接完成;这意味着发起每一个HTTP请求之前都会有一次TCP握手。 TCP协议本身握手本身就是耗费时间的,所以TCP可以保持更多的热连接来适应负载。
火狐开发者文档是如是吐槽这个模型的: 除非是要兼容一个非常古老的,不支持长连接的系统,没有一个令人信服的理由继续使用这个模型。为了缓解这些问题,长连接的概念便被设计出来了,甚至在HTTP/1.1之前。或者这被称为一个keep-alive连接。
一个长连接会保持一段时间,重复用于发送一系列请求,节省了新建TCP连接握手的时间,还可以利用TCP性能增强能力。当然这个连接也不会一直保留着: 连接在空闲一段时间后会被关闭(服务器可以使用Keep-Alive协议头来指定一个最小的连接保持时间)
但是长连接也不是完美无缺的;就算是在空闲状态,它还是会消耗服务器资源,而且在重负载时,还有可能遭受Dos attacks攻击。在这种场景下,可以使用非长连接,既尽快关闭那些空闲的连接,也能对性能有所提升。
- 增加管线化技术,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。
管线化的英文是pipelining,pipelining还有另一个意思是流水线。我看火狐开发者文档的时候,中文版将pipelining在介绍HTTP的演变为翻译为管线化,但是在介绍连接管理的时候,由将其译为流水线。我刚看的时候还以为是两种技术,事实上是一个名词的翻译。
但是火狐的开发者文档评价管线化技术,比较难用,现代浏览器默认不会启用此特性。这个特性被更好的算法所代替,也就是HTTP/2
- 支持响应分块。
简单的说这个代表分块传输,通常情况下,HTTP应答消息中发送的数据是整个发送的,Content-Length消息头部表示数据的长度,客户端需要直到那里是应答消息的结束,以及后续应答消息的开始。一个比较常见的应用是断点续传,实现H5页面的大视频播放,实现渐进式播放,不需要将整个文件加载到内存中。
值得注意的是此特性在HTTP/2.0中并不支持,HTTP/2.0提供了一种更加有效率的数据流方式。
- 引入额外的缓存控制机制。
简单的说就是引入了Cache-Control, 用Cache-control区分了缓存的类型,制定了缓存过期策略。
- 引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换。
- 凭借Host头, 能够使不同域名配置在同一个ip地址的服务器上。
有的同学看到这里会问,众所周知,HTTP用的是TCP协议,发送HTTP请求的时候,IP地址和端口必然是已知的,那么HOST的意义在哪里呢?举一个实际的例子是,Tomcat中部署多个服务,事实上一个Tomcat可以对应多个服务,现在是Spring Boot时代,Tomcat已经默认集成在里面,是一个应用对一个Tomcat。如果你开发过Servlet,还没到Spring Boot,那个时候是打war包的,war被放在webapps下面,我们在Tomcat中可以配置Host头,Tomcat会根据不同的host头转发到对应的服务上。打开Tomcat的server.xml:
### 流水线(pipelining)的设计问题
上面我们提到了HTTP 1.1引入了流水线,允许第一个响应被完全返回前,客户端发送第二个请求,我认为这是合理的设计,但是为什么现代浏览器大多没启用此特性吗?
I would always recommend going to the authoritative source when trying to understand the meaning and purpose of HTTP headers.
如果你在尝试理解HTTP头的含义和用头时,我总是建议你去原始权威文档.
上面这句话出自StackOverflow中What is HTTP "Host" header?的答案下,我挺喜欢这句话的。其实这个答案我在StackOverFlow上已经看到了答案,有同学可能会问,百度找不到吗?说句惭愧的话,找的到,但是比较费劲,Stackoverflow这种问答式网站找起问题来更快。
答案是: 流水线要求响应按请求顺序返回。
这种设计会带来队头阻塞问题(Head of line Blocking), 只要第一个HTTP流遭遇到阻塞,那么第二个响应就得一直排队等待。那为什么你要按顺序返回呢?
答案是: Because there is no identifier in the response indicating to which request it belongs.
响应没有标识符区别响应式属于哪一个请求的。
那么请问HTTP/2.0是如何解决这个问题的?
HTTP/2 solves this with stream identifiers.
HTTP / 2使用流标识符来解决了这个问题。
为了更快的速度-来吧HTTP/2
HTTP/2 的改进
HTTP/2是有官网的, 我们可以在官网看到对HTTP/2的认知
- is binary, instead of textual
传输的是二进制数据,不再是文本。
- is fully multiplexed, instead of ordered and blocking
多路复用取代了顺序和阻塞。
- can therefore use one connection for parallelism
可以并行请求
- uses header compression to reduce overhead
压缩请求减少消耗
- allows servers to “push” responses proactively into client caches
其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
is fully multiplexed 多路复用与并行请求
我们举一个小例子来说明HTTP 1.0 ==> HTTP1.1 ==> HTTP/2的变化, 为了说明这个变化,我们需要请出网购达人小明。
如果小明需要在一个淘宝店网购多个东西,在HTTP 1.0下, 不能放在一个订单里面(一个TCP连接里面),只能是一个商品一个订单。
这也太浪费时间了吧,于是小明切换到了HTTP/1.1, 虽然不用开多个订单,但其实限制也比较大,也还是只能一次订购一个,虽然最后都被算在了一个订单中(一个TCP连接)。于是小明切换到了HTTP/1.1的流水线模式,在一个订单里买了10件商品,但是他们会按照请求顺序依次到达,如果某件商品缺货或者遗失,那么小明必须等待这件商品到货或者补发到货之后,才能收到下一个商品。这也太复杂了吧。
小明马上切换到了HTTP/2模式,在这个模式下,小明可以按照任意顺序购买商品,哪个商品准备好了,哪个商品就率先发货,所以他们的到达顺序和你的购买顺序可能是不一样的,为了加速,商家还可能拆分商品。这也就是HTTP/2的多路复用,一个连接上多个请求,不再像HTTP/1.1要求的那样,要求响应按请求顺序返回。
上面这个绝妙的比喻来于StackOverFlow下What does multiplexing mean in HTTP/2这个问题的回答,这个结果颇为简单易懂。
is binary, instead of textual 二进制的而不是文本的
上面的话也就是在说,HTTP/2之前使用的是文本的,但是最终传输的不都是二进制的吗? 我们可以说二进制是令人困惑的术语,因为数据在计算机中最后都是二进制形式的。所以有什么区别呢?
为了解决我的问题,我决定使用Wireshark进行抓包,对比HTTP/1.1和HTTP/2的区别。但是我忽略了一点,目前基本上使用HTTP/2网站都是HTTPS,然后我在抓包工具中看到的就是TLS V 1.2这样的东西,这些都是密文。所以我又想用Spring Boot做一个支持HTTP/2的后台,然后自己抓包分析一下,然后发现Spring Boot 不支持HTTP/2的明文版本, 原来HTTP/2分成两个版本,一个是明文版,一个是基于加密的。但是目前浏览器和Spring Boot 只支持基于加密的版本,所以必须有加密证书,如果你禁用加密,通过浏览器进行访问的时候,浏览器会进行自动降级,将HTTP/2降级为HTTP/1.1。
所以通过自己搭建支持HTTP/2网站的想法报销了,因为比较麻烦。我只能将希望转到有支持HTTP/2明文的网站, 于是我找到了下面这篇文章:
- HTTP/2 协议抓包实战 https://zhuanlan.zhihu.com/p/...
里面给了一个HTTP/2的明文网站,遗憾的是在我去抓的时候,人家升级成HTTP/2密文了,同样的curl命令,他抓到请求中有请求升级协议的,我这里没抓到,我进到网站一看,发现人家已经是HTTPS了。所以思来想去,可能我们提出的问题本身就是由问题的,我们的问题是最终传输的时候都是二进制,所以提出的问题是有什么区别?我想下面的回答可以局部回答我们的问题:
The first is that some people have suggested that the bottom layer of the HTTP protocol is still 0 and 1. How can it be a text protocol? The answer is whether a protocol is a text protocol or not, it has nothing to do with the upper and lower layers of the network model, but only with itself.
有人认为HTTP协议的底层仍然是0和1,那为什么HTTP就算是文本协议了呢? 答案是一个协议是基于文本还是其他,不在于他的上层还是下层,仅仅在于它本身。
那你还是没回答HTTP/1.1交付给传输层的数据和HTTP/2交付给传输层的有什么区别啊? 我想大概就是在编码和格式上了。这里简单的介绍一下文本编码和二进制编码的区别,他们都是表示数据的形式。对于数字来说,一个数字比如说用二进制协议,比如98765,这是个五位数,两个字节不大够,我们大致要上三个字节来表示。那如果用文本协议呢,那就是一个字符一个字节,五个数字也就是五个字节。这就节省了两个字节。第二个就是固定了格式,将原来的Header+Body变为数个分散的帧:
为什么是HTTP/2而不是HTTP 1.2
最初的HTTP/2被称为HTTP/2.0,HTTP/2工作组给出了解释,他们认为以前的1.0,1.1造成了很多换乱和误解,让人在实际的使用难以区分差异,所以将这次的版本号定位HTTP/2,弃用次要版本号“.0”。
Java 领域对HTTP/2的支持
虽然现在HTTP/3已经出来了,但是Java领域对此支持的HTTP Client,就我熟悉的而言,还处于积极的适配HTTP/2中,Maven 仓库中的Apache HttpClient最新版本还处于4.5.2,这个目前还只是支持HTTP1.1版本。
写在最后
本篇的定位是简介,简单介绍了HTTP/2的主要特性,本身是想做抓包的,但是抓包的相关的解析又会加大大本篇的篇幅,所以考虑将报文解析移动后面的文章序列了。其实这篇文章,本身我预计打算一天完成的,后面查二进制协议和文本协议的区别,倒是让我花了不少时间,这到让我颇为意外。
参考资料
- HTTP/2 中的多路复用是什么意思 https://stackoverflow.com/que...
- Transfer-Encoding:chunked详解 https://blog.csdn.net/qq_3233...
- How does HTTP2 solve Head of Line blocking (HOL) issue https://stackoverflow.com/que...
- HTTP Head of line blocking: Why responses must come back in order? https://stackoverflow.com/que...
- What is HTTP "Host" header? https://stackoverflow.com/que...
- Why is it said that HTTP2 is a binary protocol? https://stackoverflow.com/que...
- How to enable http2 using spring boot and tomcat without SSL configuration https://stackoverflow.com/que...
- Binary vs Text https://dev.to/cacilhas/binar...
- 透视 HTTP 协议 https://zq99299.github.io/not...
- HTTP/2 官网 https://httpwg.org/specs/rfc9...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。