Web 上HTTP工作原理


Web 的工作原理是客户端使用 HTTP 协议从服务器请求资源。需要服务器连接才能确保数据可靠且安全地传输。

本文将探讨浏览器如何在 Web 上创建与服务器的连接,创建连接所需的网络往返过程,以及所有这些如何影响页面加载速度。

什么是 Web 服务器连接?

在浏览器发出 HTTP 请求以获取资源之前,首先需要与要加载资源的 Web 服务器建立连接。如果不先建立连接,数据传输将不可靠且不安全——稍后我们将解释其含义。

当你查看请求瀑布图时,可以看到服务器连接的创建过程,例如在我们免费的速度测试工具或 Chrome 开发者工具中。

你会看到三个分别用青色、橙色和紫色表示的步骤,紧随其后的绿色 HTTP 请求和蓝色下载。这三个步骤就是创建连接的过程。

上面的截图还展示了 Chrome 为服务器连接分配的 ID。当向同一服务器发送另一个请求时,Chrome 可以重用该连接。然而,当向新服务器发出请求时,必须创建一个新的连接。

建立 HTTP 服务器连接需要哪些步骤?

通常,建立 HTTP 服务器连接需要三个步骤:

  • DNS 查询:根据域名查找服务器的 IP 地址
  • TCP 连接:确保可靠通信
  • TLS/SSL 连接:确保安全的加密通信

之后,就可以通过 HTTP 请求向服务器请求资源。

DNS 查询

IP 地址(如 12.34.456.789)用于在网络上不同计算机之间传递消息。然而,它们难以记忆,对于人类来说也不方便操作。一个网站可能会从一台服务器迁移到另一台,而我们不希望在每次发生这种情况时都更新对该网站的所有引用。

因此,我们使用域名来访问网站。域名系统 (DNS) 允许我们将一个域名(如 example.com)映射到 IP 地址。

在发送 HTTP 请求之前,我们需要进行 DNS 查询以找到服务器的 IP 地址。

你可以在命令行中使用 dig 来查找服务器的 IP 地址:

1
2
dig +short example.com
93.184.216.34

如果你知道计算机的 IP 地址,可以使用互联网协议 (IP) 向其发送消息。

在这个瀑布图中,你可以看到 DNS 查询作为第一个步骤以青色显示,表示 HTML 文档请求的第一部分。

TCP 连接

不幸的是,互联网协议并不可靠:消息可能会在传输途中丢失,而客户端对此一无所知。

消息的最大大小以及一次可以发送的消息数量也存在限制,但这些限制取决于服务器及其网络连接情况。如果网络仅支持每秒 1 兆字节的数据传输,而你每秒发送 10 兆字节的数据,大多数消息将会丢失。

因此,浏览器使用传输控制协议 (TCP) 来创建服务器连接,并确保数据可靠传输。

例如,TCP 确保:

  • 丢失的消息会被重新发送
  • 长消息会被分割成多个数据块,并且这些块会按照正确的顺序处理
  • 消息发送速率会根据网络连接的状况调整

在请求资源之前,客户端首先交换一条消息以协调数据传输方式。这种消息交换称为 TCP 握手,它建立了 TCP 连接。

你可以在截图中看到 TCP 握手以橙色标记。

TLS/SSL 连接

一旦建立了 TCP 连接,理论上浏览器可以通过它开始请求资源。然而,这里有一个问题:消息不仅可以被接收方读取,沿途的每个网络基础设施也能读取它。

这意味着你家中的路由器、你手机或笔记本连接的设备可以读取你的消息。你的互联网服务提供商可以看到消息的内容。拥有海底光缆的互联网骨干服务提供商也能看到你的消息。这些网络节点还可以拦截消息,假冒你试图访问的网站。

传输层安全协议(TLS)用于保护 TCP 连接。客户端会加密它想发送给服务器的消息,这样沿途的网络节点只能看到元数据,例如数据包的数量或目标 IP 地址。因此,他们可以知道你正在加载哪个网站,但看不到具体的页面内容或你发送到该网站的数据。

那么,客户端和服务器如何从不安全的连接创建安全连接呢?互联网中的计算机不使用共享密码来加密和解密消息,而是使用公钥加密技术,它有两个独立的“密码”(称为密钥)。

公钥通过不安全的连接发送,可以用来加密消息。但只有私钥可以解密消息,且私钥从不通过网络传输。公钥包含在服务器的 TLS 证书中。

证书可以通过受信任的证书颁发机构(如 DigiCert 或 Let’s Encrypt)进行验证,防止沿途的设备伪装成你访问的网站。

你可能还听说过 SSL 证书和 SSL 连接。SSL 是 TLS 之前的一个旧协议,虽然它已经不再使用,但人们仍然常用这个旧名来指代加密连接。

为了建立安全连接,浏览器和网站服务器会在不安全的 TCP 连接上进行 TLS 握手。这个截图显示了以紫色标记的 TLS 握手。

在建立安全的 TLS 连接后,浏览器可以使用 HTTP 协议向服务器请求它想要加载的资源。

当服务器开始发送响应时,浏览器只需下载它。在这种情况下,下载只需很短的时间。

服务器连接如何影响网站速度?

我们看到,在浏览器实际开始下载网站之前,需要经过几个步骤。每一步都需要一定时间在网络上传递消息并由服务器处理。

HTTP 步骤显示为服务器响应时间或首次字节时间 (TTFB)。

网络请求分解显示 DNS、TCP、SSL、TTFB 和下载步骤及其耗时

处理 DNS 查询或建立 TCP 或 TLS 连接相对简单,所需时间不多。在这些步骤中,消息在网络上传输的时间通常占用了最多时间。

HTTP 请求通常耗时更长,尤其是在动态生成 HTML 文档或从数据库加载数据时。

什么是网络往返时间及其决定因素?

网络往返时间(round trip time, RTT)测量从发送消息到服务器并收到回复所需的时间。这包括:

  • 从你的手机或笔记本将消息发送到你的 ISP(互联网服务提供商)
  • 通过网络将消息路由到服务器
  • 生成服务器响应并将其发送回来

互联网上两台计算机之间的 RTT 测量交换消息所需的时间。

如前所述,单单请求网站的初始 HTML 文档就需要至少 4 次网络往返。如果每次往返需要 50 毫秒,意味着请求至少需要 200 毫秒。如果往返时间为 150 毫秒,初始请求需要至少 600 毫秒。

最后一公里延迟

“最后一公里” 指的是从一个枢纽到最终目的地的最后一步。例如,邮递员可以很容易地将一大袋信件运送到全国各地,但将每封信投入正确的邮箱则需要更多工作。

在网络中,”最后一公里” 指的是终端用户与其互联网服务提供商之间的数据交换。这可能意味着将消息发送到家用路由器或通过空中传送到移动设备。

在快速的有线连接上,最后一公里的延迟通常小于 10 毫秒。然而,在 4G 网络上,40 毫秒的往返延迟更为常见。在 3G 网络中,延迟可能为 80 毫秒或更高。

以下是英国不同网络提供商的平均移动延迟数据。

互联网传播

如果你在美国打开托管在意大利的一个网站,会发生什么?从你的 ISP 到那个特定服务器没有直接路径。相反,消息会在网络上执行多个“跳跃”,直到到达最终目的地。

你可以使用 traceroute 命令或可视化工具来查看消息在网络中的移动方式。在这个例子中,消息先被传递到瑞典的一个网络节点,然后到达意大利。

消息在网络上传播需要时间。假设我们从芝加哥发送一条消息到罗马,二者相距 5000 英里。即便数据以光速传播,单程也需要 26 毫秒。往返则需要 52 毫秒。

实际上,没有直接路线,数据也不会以光速传播,因此更常见的往返延迟为 118 毫秒。

其他因素

还有许多其他因素影响网络的往返时间,例如沿途服务器处理其他消息而导致的处理时间延迟。

计算请求时长

假设我们使用的移动网络最后一公里延迟为 60 毫秒。我们向意大利的服务器发送请求,其往返延迟为 118 毫秒。假设服务器立即响应。请求总共需要多长时间?

首先,我们需要通过域名系统 (DNS) 获取 IP 地址。DNS 是一个分布式系统,如果我们访问的是一个受欢迎的网站,附近的 DNS 服务器可能已经缓存了 IP 地址。因此,这一步只需 60 毫秒,假设联系 DNS 服务器耗时不到 1 毫秒。

接下来我们需要对网站服务器进行三次往返。每次往返耗时 178 毫秒(60 + 118),总共耗时 534 毫秒。

我们得到的请求时长为 594 毫秒。这假设服务器响应很小,并完全包含在 HTTP 请求的初始响应消息中。如果我们需要下载更大的文件,则需要更多时间。

网络往返时间如何影响下载时间?

在互联网上下载资源的时长不仅取决于连接的带宽,还取决于每次网络往返的时间。

例如,如果服务器响应的大小为 1 兆字节,它不会一次性发送全部数据,因为服务器连接可能无法处理如此大的数据量,导致丢失数据包并需要重新发送。

相反,使用了一种称为 TCP 慢启动的机制,服务器开始时只并行发送 10 个数据包,然后逐渐增加发送的数据包数量,直到开始丢包。

一般规则是,最初服务器响应中可以发送 14 KB 的数据,任何额外数据都需要额外的网络往返。理论上,服务器下一次可以发送两倍的数据量,即在下一个往返中下载 28 KB 的数据。

请注意,HTTP 响应通常使用 gzip 或 Brotli 压缩,因此 14 KB 的压缩数据实际上可能相当于 50 KB 的未压缩 HTML 代码。

我们进行了一次基于实验室的性能测试,网络延迟为 1 秒。因此,我们可以清楚地看到每次往返。

测试结果如下图所示:

如果 HTML 文档的大小不超过约 10 KB,则一次网络往返就足够下载响应。之后最多可以下载 38 KB 的数据,然后再次需要另一次往返。请谨慎使用这些数据,因为可能存在小的测量误差。

HTTP/2 相比 HTTP/1.1 有哪些优势?

HTTP/2 是 2015 年发布的 HTTP 协议新版本。

HTTP/2 的主要优势是可以通过同一个连接同时进行多个请求。而在使用 HTTP/1.1 加载多个资源时,需要建立多个服务器连接。

让我们来看一个通过 HTTP/1.1 加载的网站,重点关注连接 88。当连接首次建立时,我们可以看到浏览器执行了 DNS 查询,接着通过 TCP 连接并进行 TLS 握手。

同一个连接可以再次使用,但只能在初始请求完成之后。截图显示了两个后续请求依次完成。

然而,浏览器还创建了三个额外的连接(#123、#127 和 #133)到同一服务器,以加载其他资源。由于 IP 地址已经知道,不需要再次执行 DNS 查询。

如果仔细观察,你可能还会注意到连接 #84 在瀑布图中没有显示连接步骤。这是 Chrome 猜测在加载 HTML 文档后可能还需要更多连接,因此预先创建的连接。因此,当发出第一个请求时,Chrome 实际上创建了两个连接。

浏览器对单一来源最多只创建 6 个连接。当达到最大连接数时,其他请求会排队等待可用的连接。在瀑布图中,这显示为灰色的“等待”时间。

排队请求意味着它们的完成时间更长,每个连接都会消耗额外带宽,比如证书交换。

相比之下,HTTP/2 网站可以通过单个连接并行加载多个资源。

HTTP/3 对服务器连接意味着什么?

HTTP/3 只需要一次往返即可建立安全可靠的连接。它不再使用 TCP 协议,而是使用 UDP 和 QUIC。

然而,并不是所有服务器都支持 HTTP/3,因此浏览器仍然需要先建立 TCP 连接并使用旧版本的 HTTP 协议。

服务器会返回一个 HTTP 头部,告诉浏览器它支持 HTTP/3,浏览器会切换到该协议。如果将来再次创建连接,HTTP/3 可以直接使用。

什么是凭证连接?

我们提到过,HTTP/2 可以使用单个连接来发起多个请求,但在某些情况下,你可能仍会看到第二个连接被建立到服务器。

某些连接是“凭证连接”,这意味着在发出请求时会发送 cookie 和其他数据。大多数浏览器会为有凭证请求和无凭证请求创建不同的连接。

下图展示了一次凭证的 JavaScript 请求使用了与 crossorigin="anonymous" 请求不同的连接。

鉴于凭证是作为 HTTP 连接的一部分发送的,且与连接本身无关,是否有必要使用单独的连接?不一定,Microsoft Edge 使用相同的服务器连接处理这两种类型的请求。

TLS 1.2 和 TLS 1.3 的性能差异是什么?

TLS 1.3 比 TLS 1.2 更快,因为它只需要一次网络往返即可建立安全连接。而使用 TLS 1.2 的安全连接则需要两次往返,因此建立连接所需的时间更长。

在这个请求瀑布图中,可以看到 www.bbc.com 使用 TLS 1.3 只需要一次往返进行连接。然而,另外两个服务器使用的是 TLS 1.2,建立连接花费的时间较长。

内容分发网络(CDN)如何影响服务器连接?

内容分发网络(CDN)通过在全球范围内布置服务器,用户可以连接到离他们更近的服务器,从而减少网络往返时间。

通常,CDN 还会提供缓存的响应,意味着不需要向源服务器发出请求。假设使用快速的 WiFi 连接且 CDN 节点靠近用户,网络往返可能只需 10 毫秒,而整个 HTTP 请求加上建立连接可能只需 40 毫秒。

即使响应不能缓存,CDN 也能加快建立初始服务器连接的时间。然后,CDN 会将请求转发到源服务器,而源服务器可能离用户较远。

需要注意的是,在某些情况下,仅为部分资源使用 CDN 可能会降低页面速度。如果您的主网站是 example.com,而 CDN 位于 cdn.com,那么需要建立第二个连接到 CDN 服务器。而在某些情况下,直接从主域加载资源可能更快,因为可以重用现有连接。

加载网站的其他页面时的服务器连接

在首次打开网站后,加载同一站点的另一个页面通常会更快,因为某些资源已被缓存并可以重复使用。这也适用于在初次页面加载后仍保持打开的服务器连接。

这个瀑布图展示了第二次加载页面的情况。即使需要通过 HTTP 重新加载资源,也可以重用现有的服务器连接。

如何在 Chrome DevTools 中查看服务器连接步骤

Chrome 开发者工具的网络标签显示了请求瀑布图,其中包括连接的往返时间(如适用)。

但是,如果你之前已经加载过页面,请求分解中可能不会显示连接步骤。

这是因为 Chrome 会重用现有的连接,DNS 响应也会被操作系统缓存。如果你需要这些信息,可以在重新加载页面前清除缓存。

运行网站速度测试查看服务器连接

您可以使用我们免费的网页速度测试工具,查看网站加载了哪些资源,以及服务器连接如何影响性能。

在请求标签中,您可以查看网站的请求瀑布图。

您还可以通过“列”下拉菜单自定义每个请求的显示信息。例如,您可以显示每个连接的标识符以及连接协议。