- HTTP1
- HTTP1协议的这种格式,缺点也是很明显的
- 额外占用了很多字节,比如众多的回车符、换行符,它们都是字符,都需要一个字节
- 通常一个HTTP1的请求,都会携带各种请求头,我们可以通过请求头来指定请求体的压缩方式
- 但是我们没有地方可以指定请求头的压缩方式
- 不能并发的发送请求,因为不知道这个响应结果对应的到底是哪一个HTTP1请求
- 可以在请求头和响应头中做一个标记
- HTTP1协议的这种格式,缺点也是很明显的
- HTTP2
-
- 帧长度,用三个字节来存一个数字,这个数字表示当前帧的实际传输的数据的大小,3个字节表示的最大数字是2的24次方(16M),所以一个帧最大为9字节+16M
- 帧类型,占一个字节,可以分为数据帧和控制帧
- 数据帧又分为:HEADERS 帧和 DATA 帧,用来传输请求头、请求体的
- 控制帧又分为:SETTINGS、PING、PRIORITY,用来进行管理的
- 标志位,占一个字节,可以用来表示当前帧是整个请求里的最后一帧,方便服务端解析
- 流标识符,占4个字节,在Java中也就是一个int,不过最高位保留不用,表示Stream ID
- 实际传输的数据Payload
- 如果帧类型是HEADERS,那么这里存的就是请求头
- 如果帧类型是DATA ,那么这里存的就是请求体
- 如果帧的类型是HEADERS ,那就进行压缩请求头,当然压缩算法是固定的HPACK算法,不能更换
-
- HTTP2-Stream
- 流标识符,表示Stream ID,表示一个“虚拟流”
- 可以在一个TCP连接中,同时维护多个Stream,每一个帧都是属于某一个Stream
- 也就是说客户端在一个TCP连接上,可以并发的给服务端同时发送多个帧
- 流标识符,表示Stream ID,表示一个“虚拟流”
- HTTP2发送一个请求时
- 新建一个TCP连接(三次握手)
- 新建一个Stream,生成一个新的StreamID,生成一个控制帧
- 帧里记录了前面生成出来的StreamID,通过TCP连接发送出去
- 生成一个要发送的请求对应的HEADERS 帧,用来发送请求头,也是key:value的格式
- 先利用ascii进行编码,然后利用HPACK算法进行压缩
- 最终把压缩之后的字节存在帧中的Payload区域
- 记录好StreamID,最后通过TCP连接把这个HEADERS 帧发送出去
- 最后把要发送的请求体数据按指定的压缩算法(请求中所指定的压缩算法,比如gzip)进行压缩
- 把压缩之后的字节生成DATA 帧,记录好StreamID,通过TCP连接把DATA 帧发送出去
- 对于服务端而言
- 会不断的从TCP连接接收到某些帧
- 当接收到一个控制帧时,表示客户端要和服务端新建一个Stream,在服务端记录一下StreamID
- 比如在Dubbo3.0的源码中会生成一个ServerStreamObserver的对象
- 当接收到一个HEADERS 帧,取出StreamID,找到对应的ServerStreamObserver对象,并解压得到请求头
- 把请求头信息保存在ServerStreamObserver对象中
- 当接收到一个DATA 帧时,取出StreamID,找到对应的ServerStreamObserver对象
- 根据请求头的信息看如何解压请求体
- 解压之后就得到了原生请求体数据,然后按业务逻辑处理请求体
- 处理完了之后,就把结果也生成 HEADERS 帧和 DATA 帧发送客户端
- 客户端此时就变成了服务端,来处理响应结果
- 客户端接收到响应结果的HEADERS 帧,是也先解压得到响应头,记录响应体的解压方式
- 然后继续接收到响应结果的DATA 帧,解压响应体,得到原生的响应体,处理响应体
- 对于Triple协议而言,我们主要理解HTTP2中的Stream、HEADERS 帧、DATA 帧就可以了
上一篇
Dubbo-Triple
2024-06-13
下一篇
Dubbo-互调
2024-06-13