目录
- 一、HTTP/2背景
- 二、HTTP/2特性
-- 二进制传输
- 三、HTTP/2连接过程
- 四、HTTP/2基石frame
-- frame结构
-- SETTINGS
-- WINDOW_UPDATE
-- HEADERS
-- DATA
-- PUSH_PROMISE
-- GOAWAY
- 五、其它
一、HTTP/2背景
HTTP/2即超文本传输协议,是下一代HTTP协议。是由互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小组进行开发。是自1999年http1.1发布后的首个更新。HTTP 2.0在2013年8月进行首次合作共事性测试。在开放互联网上HTTP/2将只用于https://网址,而 http://网址将继续使用HTTP/1,目的是在开放互联网上增加使用加密技术,以提供强有力的保护去遏制主动攻击。HTTP/2以 Google的SPDY/2 为基础开发,实现异步连接多路复用、头部压缩、请求/响应管线化等目标。
二、HTTP/2特性
1.二进制传输
HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 的文本格式。二进制格式在协议的解析和优化扩展上带来更多的优势和可能
2.消息头压缩
HTTP/2 对消息头采用 HPACK 进行压缩传输,能够节省消息头占用的网络的流量。不像 HTTP/1.x 每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。头压缩能够很好的解决该问题
3.多路复用
HTTP/1.x 有个问题叫队头堵塞,它是指一个连接(connection)一次只提交一个请求的效率比较高, 多了就会变慢,在应对并发的时候,往往客户端必须通过创建连接池实现,而HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”
4.服务推送
当连接创建时,服务端也能够更快的把资源主动推送给客户端。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 再发送这些请求
5.流量控制
HTTP/2上面每个流都拥有自己的公示的流量窗口,它可以限制另一端发送数据。对于每个流来说,两端都必须告诉对方自己还有更多的空间来接受新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据
三、HTTP/2连接过程
上图详细展示了客户端和服务端采用HTTP/2协议通信整个过程,包括创建连接、发送接受消息、结束。为了说明上述流程我们先来了解流(Stream)、消息(Message) 和帧(Frame)
- Stream 处于一个连接中的双向二进制数据流,可以包含一个或者多个 Message。
- Message 一个完整的请求或者响应,包含多个 Frame 序列。
- Frame HTTP/2 通讯中的最小传输单位,至少含有一个 Frame header,能够表示它属于哪一个 Stream。
1.首先客户端会发一个字符串(PRI * HTTP/2.0)到服务端,表示即将要通过HTTP/2来通信
2.接着客户端发送SETTINGS帧给服务端,服务端收到后也会返回SETTINGS帧
3.客户端会发送流控给服务端,同样服务端会返回。
4.最终客户端会发送SETTINGS帧确认ack=true给服务端,同样服务端也会返回ack=true,到此通道创建完成
5.客户端发送消息请求的时候,分HEADERS和DATA帧发送,并且帧里面带有streamId来辨别是哪个消息,同样服务端也会返回HEADERS和DATA帧,带有客户端请求过来的streamId
6.关闭连接发送GO_AWAY帧
四、HTTP/2基石frame
1.frame结构
Frame 是 HTTP/2 二进制格式的基础,基本可以把它理解为它 TCP 里面的数据包一样。HTTP/2 之所以能够有如此多的新特性,正是因为底层数据格式的改变,其格式如下。
帧包括以下字段(从左往右):
payloadLength(负载长度3byte)+type(frame类型1byte)+flags(标志位1byte)+streamId(消息id3byte)+framePayload(负载内容payloadLength/byte)
eg.一串二进制数据 00 00 00 04 01 00 00 00 00
我们可以分析出它的负载长度0,帧的类型是4代表SETTINGS帧,标志为1表示true,streamId为0,表示是创建连接时候的SETTINGS 帧内容ack=true
注意:关于帧长度,需要稍加关注: - 0 ~ 2^14(16384)为默认约定长度,所有端点都需要遵守 - 2^14 (16,384) ~ 2^24-1(16,777,215)此区间数值,需要接收方设置SETTINGS_MAX_FRAME_SIZE参数单独赋值 - 一端接收到的帧长度超过设定上限或帧太小,需要发送FRAME_SIZE_ERR错误 - 当帧长错误会影响到整个连接状态时,须以连接错误对待之;比如HEADERS,PUSH_PROMISE,CONTINUATION,SETTINGS,以及帧标识符不该为0的帧等,都需要如此处理 - 任一端都没有义务必须使用完一个帧的所有可用空间 - 大帧可能会导致延迟,针对时间敏感的帧,比如RST_STREAM, WINDOW_UPDATE, PRIORITY,需要快速发送出去,以免延迟导致性能等问题
2.SETTINGS
设置帧frame type=4,接收者向发送者通告己方设定,服务器端在连接成功后必须第一个发送的帧。
字段Identifier定义了如下参数: - SETTINGS_HEADER_TABLE_SIZE (0x1),通知接收者报头表的字节数最大值,报头块解码使用;初始值为4096个字节,默认可不用设置 - SETTINGS_ENABLE_PUSH (0x2),0:禁止服务器推送,1:允许推送;其它值非法,PROTOCOL_ERROR错误 - SETTINGS_MAX_CONCURRENT_STREAMS (0x3),发送者允许可打开流的最大值,建议值100,默认可不用设置;0值为禁止创建新流 - SETTINGS_INITIAL_WINDOW_SIZE (0x4),发送端流控窗口大小,默认值2^16-1 (65,535)个字节大小;最大值为2^31-1个字节大小,若溢出需要报FLOW_CONTROL_ERROR错误 - SETTINGS_MAX_FRAME_SIZE (0x5),单帧负载最大值,默认为2^14(16384)个字节,两端所发送帧都会收到此设定影响;值区间为2^14(16384)-2^24-1(16777215) - SETTINGS_MAX_HEADER_LIST_SIZE (0x6),发送端通告自己准备接收的报头集合最大值,即字节数。此值依赖于未压缩报头字段,包含字段名称、字段值以及每一个报头字段的32个字节的开销等;文档里面虽说默认值不受限制,因为受到报头集合大小不限制的影响,个人认为不要多于2 SETTINGS_MAX_FRAME_SIZE(即2^142=32768),否则包头太大,隐患多多
标志位: * ACK (0x1),表示接收者已经接收到SETTING帧,作为确认必须设置此标志位,此时负载为空,否则需要报FRAME_SIZE_ERROR错误
3.WINDOW_UPDATE
流量控制帧frame type=8,流量控制帧,作用于单个流以及整个连接,但只能影响两个端点之间传输的DATA数据帧
字段列表: - Window Size Increment,31个比特位无符号自然数,范围为1-2^31-1(2,147,483,647)个字节数,表明发送者可以发送的最大字节数,以及接收者可以接收到的最大字节数。
4.HEADERS
头帧frame type=1,报头主要载体,请求头或响应头,同时呢也用于打开一个流,在流处于打开"open"或者远程半关闭"half closed (remote)"状态都可以发送。
字段列表: - Pad Length:受制于PADDED标志控制是否显示,8个比特表示填充的字节数。 - E:一个比特表示流依赖是否专用,可选项,只在流优先级PRIORITY被设置时有效 - Stream Dependency:31个比特表示流依赖,只在流优先级PRIORITY被设置时有效 Weight:8个比特(一个字节)表示无符号的自然数流优先级,值范围自然是(1~256),或称之为权重。只在流优先级PRIORITY被设置时有效 - Header Block Fragment:报头块分片 - Padding:填充的字节,受制于PADDED标志控制是否显示,长度由Pad Length字段决定
所需标志位: END_STREAM (0x1): 报头块为最后一个,意味着流的结束。后续可紧接着CONTINUATION帧在当前的流中,需要把CONTINUATION帧作为HEADERS帧的一部分对待 END_HEADERS (0x4): 此报头帧不需分片,完整的一个帧。后续不再需要CONTINUATION帧帮忙凑齐。若没有此标志的HEADER帧,后续帧必须是以CONTINUATION帧传递在当前的流中,否则接收者需要响应PROTOCOL_ERROR类型的连接错误。 PADDED (0x8): 需要填充的标志 PRIORITY (0x20): 优先级标志位,控制独立标志位E,流依赖,和流权重。
5.DATA
数据帧 frame type=0
字段: Pad Length: 一个字节表示填充的字节长度。取决于PADDED标志是否被设置. Data: 这里是应用数据,真正大小需要减去其他字段(比如填充长度和填充内容)长度。 * Padding: 填充内容为若干个0x0字节,受PADDED标志控制是否显示。接收端处理时可忽略验证填充内容。若验证,可以对非0x0内容填充回应PROTOCOL_ERROR类型连接异常。
标志位: END_STREAM (0x1): 标志此帧为对应标志流最后一个帧,流进入了半关闭/关闭状态。 PADDED (0x8): 负载需要填充,Padding Length + Data + Padding组成。
6.PUSH_PROMISE
服务端推送消息帧 frame type=5
字段列表: - Promised Stream ID,31个比特表示无符号的自然数,为推送保留的流标识符,后续适用于发送推送数据 - Header Block Fragment,请求头部字段值,可看做是服务器端模拟客户端发起一次资源请求
标志位: END_HEADERS(0x4/00000010),此帧包含完整的报头块,不用后面跟随CONTINUATION帧了 PADDED(0x8/00000100),填充开关,决定了下面的Pad Length和Padding是否要填充,具体和HEADERS帧内容一致
7.GOAWAY
连接关闭帧 frame type=7,一端通知对端较为优雅的方式停止创建流。
五、其它
与HTTP/1比较:
目前支持的容器与框架:netty、grpc、tomcat9、nginx
展望未来:HTTP/2定稿不久,但是其发展速度惊人,因为有众多优越的特性,还有Google作为强有力的推手,相信未来互联网应用HTTP/2将会取代HTTP/1
下面是官方给的一个HTTP/1和HTTP/2例子
https://http2.akamai.com/demo
资料:
https://github.com/fex-team/http2-spec/blob/master/HTTP2%E4%B8%AD%E8%8B%B1%E5%AF%B9%E7%85%A7%E7%89%88%2806-29%29.md
http://www.cnblogs.com/ghj1976/p/4552583.html
http://www.blogjava.net/yongboy/archive/2015/03/20/423655.html