前言

HTTP/2协议在TCP连接之初进行协商通信,只有协商成功,才会涉及到后续的请求-响应等具体的业务型数据交换。

HTTP版本标识符

  • h2,基于TLS之上构建的HTTP/2,作为ALPN的标识符,两个字节表示,0x68, 0x32,即https
  • h2c,直接在TCP之上构建的HTTP/2,缺乏安全保证,即http
  • 在HTTP/2 RFC文档出现之前,以上版本字段需要添加上草案版本号,类似于h2-11,h2c-17

HTTP/2 请求过程

针对直接建立在标准TCP之上HTTP2,在未知服务器是否提供HTTP/2支持之前,可以依赖现有HTTP/1.1进行试探。

HTTP版本的请求内容

  1. 客户端发起请求,只有请求报头:

    GET / HTTP/1. 1
    Host: server. example. com
    Connection: Upgrade, HTTP2-Settings
    Upgrade: h2c
    HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
  2. 服务器若不支持HTTP/2,直接按照HTTP/1.1响应即可
    HTTP/1. 1 200 OK
    Content-Length: 243
    Content-Type: text/html
    . . .
  3. 服务器支持HTTP/2,通知客户端一起切换到HTTP/2协议下吧

    HTTP/1. 1 101 Switching Protocols
    Connection: Upgrade
    Upgrade: h2c [ HTTP/2 connection . . .
  4. 101响应空行之后,服务器必须发送的第一个帧为SETTINGS帧(其负载可能为空)作为连接序言
  5. 客户端接收到101响应后,也必须发送一个序言作为响应,其逻辑结构:
    PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n // 纯字符串表示,翻译成字节数为24个字节
    SETTINGS帧 // 其负载可能为空

    服务器端和客户端所发送的连接序言有所不同。

  6. 客户端可以马上发送请求帧或其它帧过去,不用等待来自服务器端的SETTINGS帧
  7. 任一端接收到SETTINGS帧之后,都需要返回一个包含确认标志位SETTIGN作为确认
  8. 其它帧的正常传输

HTTP/2的直接连接

客户端预先知道服务器提供HTTP/2支持,可以免去101协议切换的流程开销。 具体流程:

  1. 客户端必须首先发送一个连接序言,其逻辑结构:

    PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n // 纯字符串表示,翻译成字节数为24个字节
    SETTINGS帧 // 其负载可能为空
  2. 发送完毕序言之后,客户端可以不用等待来自服务器端响应,马上发送HTTP/2其它帧
  3. 服务器端接收到客户端的连接序言之后,需要发送一个SETTINGS帧作为连接序言
  4. 任一端接收到SETTINGS帧之后,都需要返回一个包含确认标志位SETTIGN作为确认
  5. 其它帧的正常传输

HTTPS版本建立连接

HTTP/2安全版本在TLS上构建,协商采用的ALPN扩展协议,采用“h2”作为协议标识符(http版本则是“h2c”)。一定程度上可认为不存在试探是否支持或直接连接的烦恼,因为这个过程直接在TLS层协商而成。

流程如下:

  1. 客户端和服务器端TLS层协商
  2. 客户端发送连接序言(同上表示,PRI + SETTINGS)
  3. 接收到客户端连接序言之后,服务器端发送连接序言
  4. 双方各自确认SETTINGS帧
  5. 其它帧的正常传输

HTTPS和HTTP Upgrade方式协商

HTTPS协商是强制,封装在TLS之上ALPN扩展实现,HTTP只有非直接连接方式才会存在通过101 协议切换方式进行升级。

这里有一张图形象说明其流程。

统一的连接过程

这里不论是HTTP还是HTTPS,在两端成功协商之后(或HTTP的直接连接),其连接过程都是一样的

注意事项

  1. 客户端发起的HTTP/1.1请求,其流标识符为1,默认优先级;半关闭“half closed”状态,一旦完成HTTP/2的连接,将被应用于响应
  2. 文档提到的客户端可以通过HTTP Alternative Services(简称为[ALT-SVC],类似于CNAME机制)获得通知服务器是否支持HTTP/2,但目前看来仅仅是草案建议而已
  3. 连接序言用于最后两端协商确认双方要使用HTTP/2协议,建立初始化的HTTP/2连接环境
  4. 客户端若知服务器支持HTTP/2,可免去通过HTTP/1.1 101协议切换方式进行升级,在建立连接后即可发送序言,否则只能在接收到服务器端101响应后发送序言
  5. 建立在TLS上的HTTP/2通过ALPN扩展协商机制取代101协议切换
  6. 连接序言所包含的SETTINGS帧其负载可以为空
  7. 针对一个TCP连接,服务器第一个要发送的帧必须是SETTINGS帧
  8. 为了避免不必要延迟,客户端可以在发送完毕序言之后发送帧数据,不用等待来自服务器端的序言SETTINGS帧
  9. 客户端接收到服务器端作为序言的SETTINGS帧,需要遵守其设定
  10. 在一些环境下需要提供一个顺序机制,允许服务器在客户端发送业务帧之前发送SETTINGS,这需要客户端配合
  11. 客户端和服务器端任何一方接收到无效连接序言需要抛出PROTOCOL_ERROR类型连接错误,若收到GOAWAY帧,可忽略

小结

HTTP/2连接的建立协商机制比HTTP/1.1稍微复杂了一些。

对比明文版的HTTP/1.1和HTTP/2完成一次请求-响应:

  1. HTTP/1.1在建立建立之后,只需要发送请求报文数据
  2. HTTP/2客户端需要在连接建立之初马上发送一个连接序言过去,然后才是正常请求
  3. 两端(客户端+服务器端)的两次完整的连接序言+确认的交互流程,多了两次往返过程

在弱网络环境下,会不会加重网络负载,只能拭目一看了。

引用

  1. 《Implementing HTTP/2 client in 60 minutes》

原文 http://www.blogjava.net/yongboy/archive/2015/03/18/423570.html

HTTP/2笔记之连接建立的更多相关文章

  1. 《TCP/IP详解 卷一》读书笔记-----TCP连接建立

    1.在每个TCP报文段中,头部的flag字段里的SYN,FIN,RST,PSH可以多个有效,并没有限定为必须只有一个 2.TCP连接建立过程: 1)客户端发送一个SYN报文段,其中包含了客户端要传送的 ...

  2. gRPC的通讯过程

    在 HTTP2 协议正式开始工作前, 如果已经知道服务器是 HTTP2 的服务器, 通讯流程如下: 客户端必须首先发送一个连接序言,其逻辑结构: PRI * HTTP/2.0\r\n\r\nSM\r\ ...

  3. eShopOnContainers 知多少[11]:服务间通信之gRPC

    引言 最近翻看最新3.0 eShopOncontainers源码,发现其在架构选型中补充了 gRPC 进行服务间通信.那就索性也写一篇,作为系列的补充. gRPC 老规矩,先来理一下gRPC的基本概念 ...

  4. memcached客户端连接建立过程笔记

    memcached在启动过程初始化server_sockets时,根据启动参数决定系统是进行tcp监听还是udp监听,这里暂时只关注tcp的情况. server_socket在初始化时会向系统申请监听 ...

  5. Android学习笔记之HttpClient实现Http请求....

    PS:最近光忙着考试了....破组成原理都看吐了....搞的什么也不想干...写篇博客爽爽吧....貌似明天就考试了...sad... 学习笔记: 1.如何实现Http请求来实现通信.... 2.解决 ...

  6. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(1)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  7. 《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记

    章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...

  8. think in java 读书笔记 2 —— 套接字

    目录 think in java 读书笔记 1 ——移位 think in java 读书笔记 2 —— 套接字 think in java 读书笔记 3 —— 数据报 概要 1. 套接字基本知识 2 ...

  9. DBus学习笔记

    摘要:DBus作为一个轻量级的IPC被越来越多的平台接受,在MeeGo中DBus也是主要的进程间通信方式,这个笔记将从基本概念开始记录笔者学习DBus的过程 [1] DBus学习笔记一:DBus学习的 ...

随机推荐

  1. Android——列表视图 ListView(二)SimpleAdapter

    SimpleAdapter:可显示文字加图片 activity_activitysimple.xml <?xml version="1.0" encoding="u ...

  2. java中常见的异常(转)

    1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存在的对 ...

  3. 【高可用HA】Apache (2) —— Mac下安装多个Apache Tomcat实例

    Mac 下安装多个Apache Tomcat实例 tomcat版本:tomcat-8.0.29 参考来源: Installing Tomcat 7.0.x on OS X 在mac系统安装Apache ...

  4. Golang 类型转换整理

    1.整形到字符串: var i int = 1 var s string s = strconv.Itoa(i) 或者 s = FormatInt(int64(i), 10) 2.字符串到整形 var ...

  5. 标准Drupal7安装中文翻译出错解决办法

    这个问题在网上解决的方案一致都是说在\sites\default\settings.php文件,在最后增加以下两行: ini_set('memory_limit', '1280M'); //加大php ...

  6. Qt Quick的国际化和本地化

    国际化您的应用程序 以下部分描述了国际化QML源代码的各个方面.如果您对应用程序中的所有用户界面组件都遵循这些指南,则可以针对不同语言和本地文化约定(例如日期和数字的格式化方式)本地化应用程序的各个方 ...

  7. Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization”

    Linux 克隆虚拟机引起的“Device eth0 does not seem to be present, delaying initialization” 虚拟机Vmware上克隆了一个Red ...

  8. 使用 OpCache 提升 PHP 5.5+ 程序性能

    说明 PHP 5.5 以后内建了 OpCache , OpCache 的加速原理是把编译后的 bytecode 存储在内存里面, 避免重复编译 PHP 所造成的资源浪费. 引用 How To Enab ...

  9. 在JavaScript里写类层次结构?别那么做!

    从理论上讲,JavaScript并没有类.在实践中,下面的代码片段被广泛认为是JavaScript“类”的一个例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 fu ...

  10. C的内存四大区

    前提 看视频得来的内容,只知道不止4个区,但主要是这4个区. 四区 静态区 用于存放所有的全局变量和静态变量. ; //静态区 int main(){ ; //静态区 ; } 代码区 就是存放程序的执 ...