网控科技网

而在 HTTP/2 就不需要了,因为 HTTP/2 所有的请求都可

简介: 而在 HTTP/2 就不需要了,因为 HTTP/2 所有的请求都可以在一个 TCP 连接发送。

(此图在网上找来的,侵删)HTTP 概述HTTP 超文本传输协议是位于 TCP/IP 结构中的应用层协议,它是万维网数据通信的基础。

当我们访问一个网站时,需要通过统一资源定位符(uniform resource locator,URL)来定位服务器并获取资源。

<协议>://<域名>:<端口>/<路径>一个 URL 的一般形式通常如上所示(http://test.com/index.html ),现在最常用的协议就是 HTTP,HTTP 的默认端口是 80,通常可以省略。

HTTP/1.1HTTP/1.1 是目前使用最广泛的版本,一般没有特别标明版本都是指 HTTP/1.1。

HTTP 连接建立过程我们来看一下在浏览器输入 URL 后获取 HTML 页面的过程。

TCP 三次握手和四次挥手由于 HTTP 是基于 TCP 的,所以打算在这补充一下 TCP 连接建立和的过程。

首先,我们需要了解一些 TCP 报文段的字段和标志位:32 比特的序号字段和确认号字段,TCP 字节流每一个字节都按顺序编号。

ACK 标志位,用于指示确认字段中的值是有效的 ACK=1 有效,ACK=0 无效。

SYN 标志位,用于连接建立,SYN 为 1 时,表明这是一个请求建立连接报文。

TCP 三次握手建立连接TCP 标准规定,ACK 报文段可以携带数据,但不携带数据就不用消耗序号。

客户端发送一个不包含应用层数据的 TCP 报文段,首部的 SYN 置为 1,随机选择一个初始序号(一般为 0)放在 TCP 报文段的序号字段中。

(SYN 为 1 的时候,不能携带数据,但要消耗掉一个序号)TCP 报文段到达服务器主机后,服务器提取报文段,并为该 TCP 连接分配缓存和变量。

然后向客户端发送允许连接的 ACK 报文段(不包含应用层数据)。

这个报文段的首部包含 4 个信息:ACK 置 为 1,SYN 置为 1;确认号字段置为客户端的序号 + 1;随机选择自己的初始序号(一般为 0)。

收到服务器的 TCP 响应报文段后,客户端也要为该 TCP 连接分配缓存和变量,并向服务器发送一个 ACK 报文段。

这个报文段将服务器端的序号 + 1 放置在确认号字段中,用来对服务器允许连接的报文段进行响应,因为连接已经建立,所以 SYN 置为 0。

最后一个阶段,报文段可以携带客户到服务器的数据。

并且以后的每一个报文段,SYN 都置为 0。

下图是一个具体的示例:(此截图是我使用 Wireshark 抓包工具截取的 TCP 报文段截图)。

TCP 四次挥手连接FIN 报文段即使不携带数据,也要消耗序号。

客户端发送一个 FIN 置为 1 的报文段。

服务器发送 FIN 置为 1 的报文段。

当 A 给 B 发送 FIN 报文时,代表 A 不再发送报文,但仍可以接收报文。

B 可能还有数据需要发送,因此先发送 ACK 报文,告知 A “我知道你想断开连接的请求了”。

这样 A 便不会因为没有收到应答而继续发送断开连接的请求(即 FIN 报文)。

B 在处理完数据后,就向 A 发送一个 FIN 报文,然后进入 LAST_ACK 阶段(超时等待)。

A 向 B 发送 ACK 报文,双方都断开连接。

HTTP 报文格式HTTP 报文由请求行、首部、实体主体组成,它们之间由 CRLF(回车换行符) 分隔开。

注意:实体包括首部(也称为实体首部)和实体主体,sp 即是空格 space。

请求行和首部是由 ASCII 文本组成的,实体主体是可选的,可以为空也可以是任意二进制数据。

请求报文格式:响应报文格式:一个请求或响应报文由以下字段组成:请求方法,客户端希望服务器对资源执行的动作。

请求 URL,命名了所请求的资源。

协议版本,报文所使用的 HTTP 版本。

原因短语,数字状态码的可读版本(例如上面的响应示例跟在 200 后面的 OK,一般按规范写最好)。

一个 HTTP 请求示例:一个 HTTP 响应示例:方法GET 和 HEAD其中 GET 和 HEAD 被称为安全方法,因为它们是幂等的(如果一个请求不管执行多少次,其结果都是一样的,这个请求就是幂等的),类似于 POST 就不是幂等的。

HEAD 方法和 GET 方法很类似,但服务器在响应中只返回首部。

使用 HEAD,可以:在不获取资源的情况下了解资源的情况。

服务器开发者必须确保返回的首部与 GET 请求所返回的首部完全相同。

遵循 HTTP/1.1 规范,就必须实现 HEAD 方法。

PUT与 GET 方法从服务器读取文档相反,PUT 方法会向服务器写入文档。

PUT 方法的语义就是让服务器用请求的主体部分来创建一个由所请求的 URL 命名的新文档。

每个中间节点都可能会修改原始的 HTTP 请求,TRACE 方法允许客户端在最终发起请求时,看看它变成了什么样子。

行程最后一站的服务器会弹回一条 TRACE 响应,并在响应主体中携带它收到的原始请求报文。

这样客户端就可以查看在所有中间 HTTP 应用程序组成的请求/响应链上,原始报文是否被毁坏或修改过。

TRACE 方法主要用于诊断,用于验证请求是否如愿穿过了请求/响应链。

TRACE 请求中不能带有实体的主体部分。

TRACE 响应的实体主体部分包含了响应服务器收到的请求的精确副本。

OPTIONSOPTIONS 方法请求 Web 服务器告知其支持的各种功能。

DELETEDELETE 方法就是让服务器删除请求 URL 所指定的资源。

状态码300~399 重定向状态码重定向状态码要么告诉客户端使用替代位置来访问他们感兴趣的资源,要么一个替代的响应而不是资源的内容。

如果资源已被移动,可以发送一个重定向状态码和一个可选的 Location 首部来告知客户端资源已被移走,以及现在在哪里可以找到它。

400~499 客户端错误状态码有时客户端会发送一些服务器无法处理的东西,例如格式错误的请求报文、一个不存在的 URL。

500~599 服务器错误状态码有时客户端发送了一条有效请求,服务器自身却出错了。

以下是一些常见的通用首部:请求首部请求首部是只在请求报文中有意义的首部,用于说明请求的详情。

实体首部实体首部了有关实体及其内容的大量信息,从有关对象类型的信息,到能够对资源使用的各种有效的请求方法。

性能优化1. 减少 HTTP 请求每发起一个 HTTP 请求,都得经历三次握手建立 TCP 连接,如果连接只用来交换少量数据,这个过程就会严重降低 HTTP 性能。

所以我们可以将多个小文件合成一个大文件,从而减少 HTTP 请求次数。

其实由于持久连接(重用 TCP 连接,以消除连接及关闭时延;HTTP/1.1 默认开启持久连接)的存在,每个新请求不一定都需要建立一个新的 TCP 连接。

但是,浏览器处理完一个 HTTP 请求才能发起下一个,所以在 TCP 连接数没达到浏览器规定的上限时,还是会建立新的 TCP 连接。

从这点来看,减少 HTTP 请求仍然是有必要的。

2. 静态资源使用 CDN内容分发网络(CDN)是一组分布在多个不同地理位置的 Web 服务器。

CDN 就是为了解决这一问题,在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。

3. 善用缓存为了避免用户每次访问网站都得请求文件,我们可以通过添加 Expires 头来控制这一行为。

Expires 设置了一个时间,只要在这个时间之前,浏览器都不会请求文件,而是直接使用缓存。

具体做法是把资源地址 URL 的修改与文件内容关联起来,也就是说,只有文件内容变化,才会导致相应 URL 的变更,从而实现文件级别的精确缓存控制。

我们会很自然的联想到利用数据摘要要算法对文件求摘要信息,摘要信息与文件内容一一对应,就有了一种可以精确到单个文件粒度的缓存控制依据了。

4. 压缩文件压缩文件可以减少文件时间,让用户体验性更好。

gzip 是目前最流行和最有效的压缩方法。

可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能。

举个例子,我用 Vue 开发的项目构建后生成的 app.js 文件大小为 1.4MB,使用 gzip 压缩后只有 573KB,体积减少了将近 60%。

5. 通过 max-age 和 no-cache 实现文件精确缓存通用消息头部 Cache-Cool其中有两个选项:max-age: 设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。

no-cache: 指定 no-cache 表示客户端可以缓存资源,每次使用缓存资源前都必须重新验证其有效性。

这样每次访问网站时,浏览器都会询问 index.html 是否有更新,如果没有,就使用旧的 index.html 文件。

如果有更新,就读取新的 index.html 文件。

当加载新的 index.htm 时,也会去加载里面新的 URL 资源。

HTTPSHTTPS 是最流行的 HTTP 安全形式,由网景公司首创,所有主要的浏览器和服务器都支持此协议。

使用 HTTPS 时,所有的 HTTP 请求和响应数据在发送之前,都要进行加密。

SSL/TLS 协议作用在 HTTP 协议之下,对于上层应用来说,原来的发送/接收数据流程不变,这就很好地兼容了老的 HTTP 协议。

要想了解 HTTPS 为何安全,还得继续了解一下这些概念:加密算法、摘要算法、数字签名和数字证书。

公钥密码的加密和有如下特点:密钥对产生器产生出接收者 B 的一对密钥,即加密密钥 PK 和密钥 SK。

发送者 A 用 B 的公钥 PK 作为加密密钥来加密信息,B 接收后用密钥 SK 。

即可以有多人持有 B 的公钥,但只有 B 才能。

看上图,任何人都能用 A 的公钥 PK 对密文进行 E 运算后得到 A 发送的明文。

可见这种通信并非为了保密,而是为了进行签名和核实签名,即确认此信息是 A 发送的(使用 A 的密钥进行加密的报文,只有使用 A 的公钥才能正确)。

但上述过程仅对报文进行了签名,对报文 X 本身却未保密,所以要采用下图的方法,同时实现通信和数字签名。

HTTPS 连接建立过程HTTPS 连接建立过程和 HTTP 差不多,区别在于 HTTP(默认端口 80) 请求只要在 TCP 连接建立后就可以发起,而 HTTPS(默认端口 443) 在 TCP 连接建立后,还需要经历 SSL 协议握手,成功后才能发起请求。

我知道肯定会有人不满足于简化版的 SSL 握手过程,所以我找了一篇文章SSL/TLS 握手过程详解,这篇文章非常详细的讲解了 SSL 握手的每一步骤。

HTTP/2HTTP/2 是 HTTP/1.x 的扩展,而非替代。

所以 HTTP 的语义不变,的功能不变,HTTP 方法、状态码、URL 和首部字段等这些核心概念也不变。

之所以要递增一个大版本到 2.0,主要是因为它改变了客户端与服务器之间交换数据的方式。

HTTP 2.0 增加了新的二进制分帧数据层,而这一层并不兼容之前的 HTTP 1.x 服务器及客户端——是谓 2.0。

HTTP/2 连接建立过程现在的主流浏览器 HTTP/2 的实现都是基于 SSL/TLS 的,也就是说使用 HTTP/2 的网站都是 HTTPS 协议的,所以本文只讨论基于 SSL/TLS 的 HTTP/2 连接建立过程。

基于 SSL/TLS 的 HTTP/2 连接建立过程和 HTTPS 差不多。

在 SSL/TLS 握手协商过程中,客户端在 ClientHello 消息中设置 ALPN(应用层协议协商)扩展来表明期望使用 HTTP/2 协议,服务器用同样的方式回复。

通过这种方式,HTTP/2 在 SSL/TLS 握手协商过程中就建立起来了。

HTTP/1.1 的问题1. 队头阻塞在 HTTP 请求应答过程中,如果出现了某种情况,导致响应一直未能完成,那后面所有的请求就会一直阻塞着,这种情况叫队头阻塞。

2. 低效的 TCP 利用由于 TCP 慢启动机制,导致每个 TCP 连接在一开始的时候传输速率都不高,在处理多个请求后,才会慢慢达到“合适”的速率。

对于请求数据量很小的 HTTP 请求来说,这种情况就是种灾难。

3. 臃肿的消息首部HTTP/1.1 的首部无法压缩,再加上 cookie 的存在,经常会出现首部大小比请求数据大小还大的情况。

4. 受限的优先级设置HTTP/1.1 无法为重要的资源指定优先级,每个 HTTP 请求都是一视同仁。

在继续讨论 HTTP/2 的新功能之前,先把 HTTP/1.1 的问题列出来是有意义的。

因为 HTTP/2 的某些新功能就是为了解决上述某些问题而产生的。

二进制分帧层HTTP/2 是基于帧的协议。

而 HTTP/1.1 是以文本分隔的。

解析 HTTP/1.1 不需要什么高科技,但往往速度慢且容易出错。

你需要不断地读入字节,直到遇到分隔符 CRLF 为止,同时还要考虑不守规矩的客户端,它只会发送 LF。

解析 HTTP/1.1 的请求或响应还会遇到以下问题:一次只能处理一个请求或响应,完成之前不能停止解析。

HTTP/2 有了帧,处理协议的程序就能预先知道会收到什么,并且 HTTP/2 有表示帧长度的字段。

帧结构由于 HTTP/2 是分帧的,请求和响应都可以多路复用,有助于解决类似类似队头阻塞的问题。

帧类型多路复用在 HTTP/1.1 中,如果客户端想发送多个并行的请求,那么必须使用多个 TCP 连接。

而 HTTP/2 的二进制分帧层突破了这一限制,所有的请求和响应都在同一个 TCP 连接上发送:客户端和服务器把 HTTP 消息分解成多个帧,然后乱序发送,最后在另一端再根据流 ID 重新组合起来。

这个机制为 HTTP 带来了巨大的性能提升,因为:可以并行交错地发送请求,请求之间互不影响;可以并行交错地发送响应,响应之间互不干扰;只使用一个连接即可并行发送多个请求和响应;消除不必要的延迟,从而减少页面加载的时间;不必再为绕过 HTTP 1.x 限制而多做很多工作;流HTTP/2 规范对流的定义是:HTTP/2 连接上独立的、双向的帧序列交换。

由于有分帧,所以多个请求和响应可以交错,而不会互相阻塞。

客户端到服务器的 HTTP/2 连接建立后,通过发送 HEADERS 帧来启动新的流。

如果首部需要跨多个帧,可能还会发送 CONTINUATION 帧。

后续流启动的时候,会发送一个带有递增流 ID 的新 HEADERS 帧。

消息HTTP 消息泛指 HTTP 请求或响应,消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流 ID 重新组装。

一个消息至少由 HEADERS 帧(它初始化流)组成,并且可以另外包含 CONTINUATION 和 DATA 帧,以及其他的 HEADERS 帧。

HTTP/1.1 的请求和响应部分都分成消息首部和消息体两部分;HTTP/2 的请求和响应分成 HEADERS 帧和 DATA 帧。

优先级把 HTTP 消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,进一步提升性能。

通过 HEADERS 帧和 PRIORITY 帧,客户端可以明确地和服务器沟通它需要什么,以及它需要这些资源的顺序。

具体来讲,服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。

流量控制在同一个 TCP 连接上传输多个数据流,就意味着要共享带宽。

为解决这个问题,HTTP/2 为数据流和连接的流量控制了一个简单的机制:流量控制基于每一跳进行,而非端到端的控制;流量控制基于 WINDOW_UPDATE 帧进行,即接收方广播自己准备接收某个数据流的多少字节,以及对整个连接要接收多少字节;流量控制窗口大小通过 WINDOW_UPDATE 帧更新,这个字段指定了流 ID 和窗口大小递增值;流量控制有方向性,即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小;流量控制可以由接收方禁用,包括针对个别的流和针对整个连接。

HTTP/2 连接建立之后,客户端与服务器交换 SETTINGS 帧,目的是设置双向的流量控制窗口大小。

服务器推送HTTP/2 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。

换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。

通常的 Web 应用都由几十个资源组成,客户端需要分析服务器的文档才能逐个找到它们。

首部压缩HTTP/1.1 存在的一个问题就是臃肿的首部,HTTP/2 对这一问题进行了改进,可以对首部进行压缩。

在一个 Web 页面中,一般都会包含大量的请求,而其中有很多请求的首部往往有很多重复的部分。

HTTP/2 在客户端和服务器端使用“首部表”来和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送。

下面再来看一个简化的例子,假设客户端按顺序发送如下请求首部:当客户端发送请求时,它会根据首部值创建一张表:如果服务器收到了请求,它会照样创建一张表。

当客户端发送下一个请求的时候,如果首部相同,它可以直接发送这样的首部块:626364服务器会查找先前建立的表格,并把这些数字还原成索引对应的完整首部。

性能优化 使用 HTTP/2 代替 HTTP/1.1,本身就是一种巨大的性能提升。

这小节要聊的是在 HTTP/1.1 中的某些优化手段,在 HTTP/2 中是不必要的,可以取消的。

取消合并资源在 HTTP/1.1 中要把多个小资源合并成一个大资源,从而减少请求。

而在 HTTP/2 就不需要了,因为 HTTP/2 所有的请求都可以在一个 TCP 连接发送。

取消域名拆分取消域名拆分的理由同上,再多的 HTTP 请求都可以在一个 TCP 连接上发送,所以不需要采取多个域名来突破浏览器 TCP 连接数限制这一规则了。


以上是文章"

而在 HTTP/2 就不需要了,因为 HTTP/2 所有的请求都可

"的内容,欢迎阅读网控科技网的其它文章