兼容HTTP/ 1.1
第一点,HTTP/2 出来的目的是为了改善 HTTP 的性能。协议升级有一个很重要的地方,就是要兼容老版本的协议,否则新协议推广起来就相当困难, HTTP/2 做到了兼容 HTTP/1.1。
1.HTTP/2 没有在 URI 里引入新的协议名,仍然用「http://」表示明文协议,用「https://」表示加密协议,只需要浏览器和服务器在背后自动升级协议,这样可以让用户意识不到协议的升级,很好的实现了协议的平滑升级。
2.只在应用层做了改变,还是基于 TCP 协议传输,应用层方面为了保持功能上的兼容,HTTP/2 把 HTTP 分解成了「语义」和「语法」两个部分,「语义」层不做改动,与 HTTP/1.1 完全一致,比如请求方法、状态码、头字段等规则保留不变。而在「语法」层面基本改变了 HTTP 报文的传输格式。
头部压缩
第二点,对于常见的 HTTP 头部通过静态表和 Huffman 编码 的方式,将体积压缩了近一半,而且针对后续的请求头部,还可以建立动态表,将体积压缩近 90%,大大提高了编码效率,同时节约了带宽资源。
不过,动态表并非可以无限增大, 因为动态表是会占用内存的,动态表越大,内存也越大,容易影响服务器总体的并发能力,因此服务器需要限制 HTTP/2 连接时长或者请求次数。
Stream并发
第三点,HTTP/2 实现了 Stream 并发,多个 Stream 只需复用 1 个 TCP 连接,节约了 TCP 和 TLS 握手时间,以及减少了 TCP 慢启动阶段对流量的影响。不同的 Stream ID 可以并发,即使乱序发送帧也没问题,比如发送 A 请求帧 1 -> B 请求帧 1 -> A 请求帧 2 -> B 请求帧2,但是同一个 Stream 里的帧必须严格有序。
另外,可以根据资源的渲染顺序来设置 Stream 的优先级,从而提高用户体验。
服务器支持主动推送资源
第四点,服务器支持主动推送资源,大大提升了消息的传输性能,服务器推送资源时,会先发送 PUSH_PROMISE 帧,告诉客户端接下来在哪个 Stream 发送资源,然后用偶数号 Stream 发送资源给客户端。
HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,但是 HTTP/2 还是存在"队头阻塞"的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层。
存在的问题
HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。
所以引出了HTTP/3 。