【HTTP 2】启用 HTTP 2(Starting HTTP/2)

前情提要

在上一篇文章《【HTTP
2】HTTP/2 协议概述(HTTP/2 Protocol Overview)
》中,简单介绍了 HTTP 2 规范的文档结构以及约定和术语。

本文变对 HTTP 2 规范的第一部分进行介绍,来说明如何发起一个 HTTP 2 连接。

启用 HTTP/2(Starting HTTP/2)

HTTP 2 连接是一个运行在 TCP 连接之上的应用层协议。客户端是
TCP 连接的发起者。

HTTP 2 保持了 HTTP 1.1 的风格,同样使用“http”和“https”作为 URI 的开始。并且共享相同的默认端口号:“http”使用 80 端口,“https”使用 443 端口。这意味着,相关实现要处理针对目标资源的请求,比如 http://example.org/foo 或者 https://example.com/bar,需要先知道上游服务器(该客户端当前希望建立的连接)是否支持 HTTP 2。

“http”和“https”支持 HTTP 2 的手段有所不同。“http”支持 HTTP 2 的方法在 3.2
详述,而“https”支持 HTTP 2 的方法在 3.3
详述。

HTTP/2 版本标识(HTTP/2 Version Identification)

本文档中所定义的协议有两个标识符。

字符串“h2”标识了使用传输安全层(TLS)的协议。该标识符用于
TLS 应用层协议协商(ALPN)扩展(TLS-ALPN)字段,在任何 TLS 之上的 HTTP 2 都会被该标识符标记。

“h2”字符串在 ALPN 协议标识中被序列化成两个八进制序列:0x68, 0x32。

字符串“h2c”标识了 HTTP 2 运行在明文 TCP 中。该标识符用于 HTTP 1.1 Upgrade 报文头中,在任何 TCP 之上的 HTTP 2 都会被该标识符标记。

选择“h2”或“h2c”意味着将会导致不同的传输、安全性、帧构成,以及在本文档中所描述的消息语法。

“http”中启用 HTTP/2(Starting HTTP/2 for “http” URIs)

一个客户端使用“http”发起请求,并不知道下一站是否支持 HTTP 升级机制。客户端通过发送 HTTP 1.1 请求,并包括 Upgrade 报文头,以“h2c”标识。这样的 HTTP 1.1 请求必须(MUST)有且仅有一个 HTTP2-Settings 报文头字段。

例如:

1
2
3
4
5
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>

在客户端发送 HTTP 2 帧之前,包含 Payload 的请求必须(MUST)被完整的发送。这意味着一个较大的请求将会阻塞连接,直到它被完全发送完毕。

如果初始请求与后续请求的并发非常重要,OPTIONS 请求可以用于升级至 HTTP 2 ,不过需要额外增加一次通信的成本。

不支持 HTTP 2 的服务器可以视 Upgrade 报文头不存在,进行如下响应:

1
2
3
4
5
HTTP/1.1
200
OK
Content-Length:
243
Content-Type:
text/html
 
...

服务器必须(MUST)忽略 Upgrade 报文头中的“h2”标识。“h2”标识意味着基于 TLS 的 HTTP/2,应该参考 3.3
进行协商。

支持 HTTP 2 的服务器接受了升级请求,并以状态码 101(转换协议)进行响应。在 101 响应的空行后,服务器可以开始发送 HTTP 2 帧。这些帧必须(MUST)包括升级请求对应的响应。

例如:

1
2
3
4
5
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
 
[ HTTP/2 connection ...

由服务器发送的第一个 HTTP 2 帧必须(MUST)是一个服务器连接序言(Connection Preface)(参考 3.5 章),并且包含一个 SETTINGS 帧(参考章节 6.5)。根据接收的 101 响应,客户端必须(MUST)发送一个同样包含 SETTINGS 帧的连接序言(Connection Preface)(参考章节 3.5)。

在升级之前所发送的 HTTP 1.1 请求,将被分配一个流标识符 “1”(参考章节 5.1.1),其优先级为默认级别(参考章节 5.3.5)。流 “1” 从 HTTP 1.1 请求完成后,是一个从客户端至服务器的隐性“半关闭”的流(参考章节 5.1)。在开始 HTTP 2 连接后,流 “1” 被用于响应。

HTTP2-Settings 报文头(HTTP2-Settings Header Field)

一个 HTTP 1.1 请求升级至 HTTP 2,必须(MUST)包含有且仅有一个 HTTP2-Settings 报文头。HTTP2-Settings 报文头是一个特定于连接的报头字段,其中的参数用于管理 HTTP 2 连接,在服务器接收升级请求时预先提供的。

1
HTTP2-Settings    =
token68

如果没有提供 HTTP2-Settings 报文头,或者提供了超过一个该报文头,服务器不可以(MUST NOT)升级该连接至 HTTP 2。服务器也不可以(MUST NOT)发送这个报文头。

HTTP2-Settings 报文头中的内容,是一个以 Base64 编码的 SETTINGS 帧的 Payload(即:URL 和安全文件名的 Base64 描述(RFC4648)的
5 章
,任何结尾的‘=’都将被忽略)。token68 的 ABNF(RFC5234)产物在 RFC7235 有所定义。

由于升级(Upgrade)只应用于直接连接,发送 HTTP2-Settings 的客户端必须(MUST)将 HTTP2-Settings 作为连接选项,包含在 Connection 报文头中,以防止它被转发(参考 RFC7230章节
6.1
)。

服务器解码并解释这些值,并将其看做其他 SETTINGS 帧。由于 101 响应作为了隐式确认,所以显式确认这些设置(参考章节 6.5.3)是没必要的。在升级请求中提供这些值,使得一个客户端有机会在接收服务器发 送的任何帧之前提供参数信息。

“https”中启用 HTTP/2(Starting HTTP/2 for “https” URIs)

一个发起“https”请求的客户端,需要用到 TLS(TLS1.2
和应用层协议协商(ALPN) 扩展(TLS-ALPN)。

TLS 之上的 HTTP 2 使用“h2”作为协议标识符。客户端一定不能(MUST NOT)发送“h2c”协议标识符,服务器也一定不能(MUST NOT)选择“h2c”标识符使用。“h2c”协议标识符描述了不适用 TLS 的协议。

一旦 TLS 协商完成,客户端和服务器都必须(MUST)发送一个连接序言(Connection preface)。

先验下启用 HTTP/2(Starting HTTP/2 with Prior Knowledge)

客户端可以通过其他方式判断服务器是否支持 HTTP 2。例如 ALT-SVC,它描述了一种机制使得 HTTP 具有广播能力。

客户端必须(MUST)发送连接序言(Connection preface,参考章节 3.5),然后可以(MAY)立即发送 HTTP 2 帧给服务器。服务端可以通过已存在的连接序言识别出这个连接。这只对基于明文 TCP 的 HTTP 2 连接建立有影响,TLS 之上的 HTTP 2 必须(MUST)使用 TLS 协议协商(TLS-ALPN)。

同样的,服务器必须(MUST) 发送连接序言(参考章节 3.5)。

如果没有其他信息,对 HTTP 2 之前的支持并不代表着指定服务器一定会在之后的连接中支持 HTTP 2。比如,服务器配置有可能改变,或者服务器集群中不同的实例配置有差异,亦或者网络状况的变化。

HTTP 2 连接序言(HTTP/2 Connection Preface)

在 HTTP 2 中,每个终端都需要发送一个连接序言作为协议的最终确认以及 HTTP 2 的连接初始设置。客户端和服务器均需要发送一个不同的连接序言。

客户端连接序言以 24 个字节序列开始,以十六进制表示为:

1
0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a

也就是说,连接序言以字符串 PRI
* HTTP/2.0\r\n\r\nSM\r\n\r\n 
开头。这个序列后必须(MUST)跟着一个 SETTINGS 帧(参考章节 6.5),其可以(MAY)为空。客户端收到 101 (协议转换)响应后,立刻发送客户端连接序言。或者作为 TLS 连接的第一个应用数据字节。如果在语言验证服务器支持 HTTP 2 的情况下启用 HTTP 2 连接,客户端连接序言在连接建立后发送。

注意:客户端连接序言是用来让大部分 HTTP 1.1 或 HTTP 1.0 服务端及中介端不试图进一步处理帧。注意这并不能解决【TALKING】中提到的问题。

服务器连接序言包含一个可能是空的 SETTINGS 帧(参考章节 6.5),它必须在 HTTP 2 连接中首个发送。

从一个节点接收到的连接序言中所包含的 SETTINGS 帧必须在连接序言发送后被确认(参考章节 6.5.3)。

为了避免不必要的延迟,允许客户端在发送客户端连接序言之后立即发送其他额外的帧,不需要等待收到服务器端连接序言。不过,值得注意的是,服务端连接序言 SETTINGS 帧可能包含一些关于期望客户端如何与服务器端通信的必须修改的参数。在收到这些 SETTINGS 帧后,客户端应当遵守所有设置的参数。在有些配置中,服务器可能在客户端发送其他额外帧之前传输 SETTINGS,以提供一个避免这些问题的机会。

客户端和服务器必须(MUST)将一个非法的连接序言当做一个 PROTOCOL_ERROR 类型的连接错误(Connection error,参考章节 5.4.1)。在这个案例中,当一个节点不支持 HTTP 2 而出现非法序言时,GOAWAY 帧(参考章节 6.8)可以(MAY)被省略。


本文以 CC
BY-NC-SA 3.0 CN
 协议共享,转载、共享及二次创作时请保留原文出处及链接,请勿用于商业用途。

本文链接:http://litecodes.com/dev/http-2-spec-starting-http-2/

本系列文章将会在我的 GitBook:http2-spec-zh 同步更新,

下一篇文章将会翻译协议的第三部分:HTTP Frames(HTTP 帧),不要错过哟~

【HTTP 2】启用 HTTP 2(Starting HTTP/2)的更多相关文章

  1. 启用CentOS6.5 64位安装时自带的MySQL数据库服务器

    本人在虚拟机上又安装了一台linux机器,作为MySQL数据库服务器用,在安装时选择了系统自带的MySQL服务器端,以下是启用步骤. 首先开启mysqld服务 #service mysqld star ...

  2. springMVC注解启用及优化

    使用注解的原因 最方便的还是启用注解 注解方便,而且项目中很流行. 配置文件尽量减少,主要使用注解方式. Springmvc的注解是在2.5版本后有了注解,如何开启注解配置文件 Web.xml文件中不 ...

  3. CentOS 7.1 Bridge启用STP报错"Master connection not found or invalid"

    今天在公司测试Linux bridge搭建,为了使内部docker容器的网络能够不经过2层封装转发对外公布,顾试用一下bridge功能,结果碰到报错:"Bringing up interfa ...

  4. Nginx 启用 https

    在nginx.conf中增加新server配置 server { listen ; server_name www.some.com; ssl on; ssl_certificate sslkey/s ...

  5. 安装ESXi5.5遇到Relocating modules and starting up the kernel的处理

    在一些Dell较旧的服务器上安装ESXi 5.x时, 会遇到卡在Relocating modules and starting up the kernel过不去的问题. 比如我装的这台CS24VSS. ...

  6. [转]Hive:简单查询不启用Mapreduce job而启用Fetch task

    转自:http://www.iteblog.com/archives/831 如果你想查询某个表的某一列,Hive默认是会启用MapReduce Job来完成这个任务,如下: hive> SEL ...

  7. 启用VTX技术支持启动android的虚拟机 - 报错

    第一次启用VTX技术支持启动android的虚拟机,启动时提示如下错误: Starting emulator for AVD 'AVD_for_Android_TV_1080p_by_Google'e ...

  8. SpringMVC注释启用

    这篇文章是我学习的网络视频SpringMVC写的过程. 谢谢公布各位前辈的视频 以下评论SpringMVC几个关键步骤,注意事项启用: 首先需要加载配置文件(假设请使用自定义路径) <? xml ...

  9. ADS1.2和JlinkV8 erro starting external process,Process error code 87(0x57)参数错误

    ADS1.2和JlinkV8  erro starting external process,Process error code 87(0x57)参数错误 网上的大致说法是说这个跟W7有关 说是将I ...

随机推荐

  1. 帝国cms灵动标签下常用标签

    这里简单整理下灵动标签下的常用标签 标题名称:<?=$bqr['title']?>  <?=esub($bqr[title],22)?> 限制字符22个 标题链接:<?= ...

  2. qt 国际化(翻译时会触发changeEvent)

    1. 修改工程文件 .pro ,加入翻译源文件 hello_world.ts: TRANSLATIONS += \        Resource/translations/hello_world.t ...

  3. Nginx工作原理和优化、漏洞(转)

    查看安装了哪些模块命令: [root@RG-PowerCache-X xcache]# nginx/sbin/nginx -Vnginx version: nginx/1.2.3built by gc ...

  4. 宣布正式发布 Windows Azure 上的 Oracle 软件以及 Windows Azure Traffic Manager 更新

     Windows Azure 的核心原则之一就是为客户提供一个开放.灵活的平台.今天是一个令人振奋的里程碑,因为我们与 Oracle 的合作又向前迈进了一步.Oracle Database.Ora ...

  5. Hello China操作系统STM32移植指南(一)

    Hello China操作系统移植指南 首先说明一下,为了适应更多的文化背景,对Hello China操作系统的名字做了修改,修改为"Hello X",或者连接在一起,写为&quo ...

  6. MFC自绘控件学习总结

    前言:从这学期开始就一直在学习自绘控件(mfc),目标是做出一款播放器界面,主要是为了打好基础,因为我基础实在是很烂....说说我自己心得体会以及自绘控件的方法吧,算是吐槽吧,说的不对和不全的地方,或 ...

  7. EGL接口 简单介绍

    from http://lyodev.appspot.com 第二章 EGL 接口 EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接口.本章主要讲述 OpenGL ES 的 ...

  8. js如何判断一个对象是不是Array?(转载)

    js如何判断一个对象是不是Array? 在开发中,我们经常需要判断某个对象是否为数组类型,在Js中检测对象类型的常见方法都有哪些呢? typeof 操作符 对于Function, String, Nu ...

  9. http动态调用webserive

    前言 传统方式调用WebService是直接引用服务,生成客户端代理类类,这种方式将ws进行了再次封装,并以代理的方式进行调用,这种方式的优点是简单,方便. 但是此种方式不足的地方是,当对方ws接口变 ...

  10. win7如何快速设置开机启动项?

    添加开机启动项方法: 找到windows开始菜单->所有程序->启动,右键打开, 进入C:\Users\Ocean\AppData\Roaming\Microsoft\Windows\St ...