文章

浏览器中的HTTP请求过程是怎么样的?🚀

浏览器工作原理

详解浏览器中的HTTP请求过程

浏览器中的HTTP请求过程是怎么样的?🚀

前瞻

HTTP 协议是建立在 TCP 连接基础之上的,HTTP 协议是一种允许浏览器向服务器获取资源的协议,是 Web 的基础。通常由浏览器发起请求,用来获取不同类型的文件,如 HTML 文件、CSS 文件、JavaScript 文件等。此外,HTTP 也是浏览器使用最广的协议,因此,对于学好浏览器来说,了解 HTTP 协议很重要。

为什么通常在第一次访问一个站点时,打开速度很慢,当再次访问这个站点时,速度就很快了?

为什么登录过一个网站后,下次再访问这个站点时,就已经处于登录的状态了?

这一切的秘密都需要 HTTP 协议来解答。

浏览器端发起 HTTP 请求流程

  1. 构建请求

    👇

  2. 查找缓存

    👇

  3. 准备 IP 地址和端口

    👇

  4. 等待 TCP 队列

    👇

  5. 建立 TCP 连接

    👇

  6. 发送 HTTP 请求

构建请求

首先,浏览器构建请求行信息,构建好后,浏览器准备发起网络请求

// 请求行信息
GET /index.html HTTP1.1

查找缓存

在发送网络请求之前,浏览器会先在浏览器缓存中查询是否有要请求的文件。

浏览器缓存是一种在本地保存资源副本,以便下次请求时直接使用的技术

当浏览器发现请求的资源已经在浏览器缓存中存有副本时,它会去拦截请求,返回该资源的副本,并直接结束请求,而不会再去服务器重新下载了。当然,如果缓存查找失败,就会进入网络请求过程了。

  • 对于服务器来说,这样做有助于缓解服务器压力,提升性能
  • 对于浏览器来说,这样做可以实现快速资源加载

准备 IP 地址和端口

因为浏览器使用 HTTP 协议作为应用层协议,用来封装请求的文本信息,并使用 TCP/IP 协议作为传输层协议将它发送到网络上,所以在 HTTP 工作开始之前,浏览器需要通过 TCP 协议与服务器建立连接。换句话说,也就是 HTTP 的内容是通过 TCP 的传输数据阶段来实现的。

image-20230413231553324

从上图中,可以看出:

  • HTTP 请求的第一步是和服务器建立 TCP 连接
  • 建立连接的信息从哪儿来?建立 TCP 连接的第一步就是需要准备 IP 和端口号

知道了建立连接的信息在哪儿,那么如何获取这些信息呢?

  • 数据包是通过 IP 地址传输给接收端的,而 IP 地址仅仅只是一些数字标识,难以记忆,但使用域名就很容易记住一个网站了。因此,又出现了一个服务:负责把域名和 IP 地址做一一映射关系,这套将域名映射为 IP 地址的系统叫做”域名系统”,简称 DNS(Domain Name System)

那么,实际上第一步浏览器会请求 DNS 返回域名对应的 IP 地址,并且浏览器还提供了 DNS 数据缓存服务,如果某个域名已经解析过了,那么浏览器会缓存解析的结果,方便下次查询时直接使用,这样也会减少一次网络请求。拿到 IP 地址之后,就需要获取端口号了,默认情况下,如果 URL 没有特别指定端口号,那么 HTTP 协议默认为 80 端口。

等待 TCP 队列

IP 地址和端口号已经准备就绪了,是不是就可以进行 TCP 连接了呢?

⚠ 不行,因为 Chrome 有个机制:

  • 同一个域名同时最多只能建立 6 个 TCP 连接
  • 那么也就是说,如果在同一个域名下同时有 10 个请求发生,其中会有 4 个请求会进入排队等待状态,直至进行中的请求完成。当然,如果请求数量小于 6 个,会直接进入建立 TCP 连接的步骤。

建立 TCP 连接

在排队等待之后,终于能和服务器建立连接了。由于 HTTP 协议是基于 TCP 连接之上的,所以这时候 HTTP 还没出场哦。因此,在 HTTP 开始工作之前,浏览器通过 TCP 协议与服务器建立连接,在 TCP 的整个周期中,通过”三次握手”与服务器建立连接,随之进行数据的传输,然后通过”四次挥手”断开连接。

发送 HTTP 请求

有必要再提醒一下,HTTP 是基于 TCP 连接之上的协议。因此,一旦建立了 TCP 连接,浏览器就可以和服务器进行通信了,而 HTTP 中的数据就是在整个通信过程中传输的

整个 HTTP 请求的请求信息被分为三个部分:

  • 请求行
    • 请求方法
    • 请求 URI(Uniform Resource Identifier)
    • HTTP 协议版本
  • 请求头
    • Host
    • Connection
    • Cache-Control
    • User-Agent
    • 等等其他信息…
  • 请求体

浏览器是如何发送请求信息给服务器的?

首先,浏览器会向服务器发送请求行,它包括了请求方法、请求 URI 和 HTTP 协议版本。

发送请求行,就是告诉服务器浏览器需要什么资源,最常用的请求方法就是 GET 请求,如直接在浏览器地址栏输入一个域名,代表着告诉服务器要 GET 它的首页资源。

另外一个常用的请求方法就是 POST 请求,它用于向服务器发送一些数据,这些数据是通过请求体来发送的。

在浏览器发送请求行命令之后,还要以请求头的形式发送一些其他的信息,把浏览器的一些基础信息告诉服务器,如包含了浏览器所用的操作系统、浏览器内核、当前请求的域名信息、浏览器端的 Cookie 信息等等。

服务器端处理 HTTP 请求流程

  1. 响应请求

👇

  1. 断开连接

👇

  1. 重定向

响应请求

在服务器成功收到了来自浏览器的 HTTP 请求后,服务器便可以根据浏览器的需要来返回数据了。

同样地,服务器向浏览器返回响应信息时,会被分为三个部分:

  • 响应行
    • HTTP 协议版本
    • 状态码
  • 响应头
    • Content-Type
    • Connection
    • Last-Modified
    • Content-Encoding
    • 等等其他信息…
  • 响应体
    • 返回 html 文件或其他相应的资源

服务器是如何返回响应信息给浏览器的?

首先服务器会返回响应行,其中包含了状态码和 HTTP 协议版本

随后,服务器会向浏览器发送响应头,响应头包含了服务器的一些信息,如服务器生成返回数据的时间、返回的数据类型等等信息。

发送完响应头后,服务器就可以继续发送响应体的数据了,通常情况下,响应头包含了 HTML 的内容。

断开连接

通常情况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接了。

不过如果浏览器或者服务器在其头信息中加入了Connection: Keep-Alive:

Connection: Keep - Alive;

那么TCP 连接在发送后将仍然保持打开状态,这样浏览器就可以继续通过同一个 TCP 连接发送请求了。保持 TCP 连接可以省去下次请求时需要建立连接的时间,进而提升资源加载速度。如网站中的图片都来自同一个站点,那么在初始化一个持久连接后,就可以复用该连接,以请求其他资源,而不需要重新再建立新的 TCP 连接了。

重定向

当实际输入的地址和最终打开页面的地址不一样时,说明发生了重定向。

当响应行中的状态码为 301 时,即代表了重定向。在响应头中的 Location 字段代表了重定向的地址

为什么很多站点二次打开的速度会很快?

如果第二次页面打开很快,显然是因为第一次加载页面过程中,缓存了一些耗时的数据。

那哪些数据会被缓存呢?

  • DNS 缓存
  • 页面资源缓存

这两块数据会被浏览器缓存起来,相对来说,DNS 缓存比较简单了,主要就是在浏览器本地把对应的 IP 地址和域名关联起来。

而对于页面资源缓存来说,就较为复杂了,其缓存处理过程为:

image-20230414131336647

服务器是通过什么方式让浏览器缓存数据的?

从图中的第一次请求可以看出,当服务器返回 HTTP 响应头给浏览器时,浏览器是通过响应头中的 Cache-Control 字段来设置是否缓存该资源。通常,还需要为这个资源设置一个缓存过期时长,而这个时长是通过 Cache-Control 中的 Max-age 参数来设置的,如上图中的缓存过期时间是 2000 秒。这也就意味着,在该缓存资源还未过期的情况下,如果再次请求该资源,会直接返回缓存中的资源给浏览器。但如果缓存过期了,浏览器则会继续发起网络请求,并且在 HTTP 请求头中带上”If-None-Match”字段,服务器收到请求头后,会根据 If-None-Match 的值来判断请求的资源是否有更新。如果没有更新,就返回 304 状态码,相当于服务器告诉浏览器:这个缓存可以继续使用,就不重新发送数据给你了。如果资源有更新,服务器就直接返回最新资源给浏览器。

简单来说,很多网站二次访问能够提升速度,是因为这些网站把很多资源都缓存在了本地,浏览器缓存直接使用本地副本来回应请求,而不会产生真实的网络请求,从而节省了时间。同时,DNS 数据也被浏览器缓存了,也节约了 DNS 查询的时间。

登录状态是如何保持的?

通常情况下,用户打开登录页面,输入用户名和密码,点击确定按钮并触发页面脚本生成用户登录信息,调用 POST 方法将用户信息提交给服务器。

服务器接收到浏览器提交的信息后,查询后台,验证用户登录信息是否正确,如果正确的话,则会生成一段表示用户身份的字符串,并把该字符串写到响应头的 Set-Cookie 字段里,然后把响应头发送给浏览器。

Set-Cookie: UID=216uad

浏览器在接收到服务器的响应头后,进行解析响应头,如果响应头中包含 Set-Cookie 字段时,浏览器就会把这个字段信息保存到本地。当用户再次访问时,浏览器会发起 HTTP 请求,但在发起请求之前,浏览器会读取之前保存的 Cookie 数据,并把数据写进请求头里的 Cookie 字段里,然后浏览器再将请求头发送给服务器。

Cookie: UID=216uad

服务器在收到 HTTP 请求头数据后,就会查找请求头中的 Cookie 字段信息,当查找到包含 UID=216uad 的信息时,服务器查询后台,并判断该用户是已登录状态,然后生成含有该用户信息的页面数据,并把生成的数据返回给浏览器。浏览器在接收到含有当前用户的页面数据后,就可以正确地展示用户登录的状态信息了。

简单来说,如果服务器端发送的响应头中有 Set-Cookie 字段,那么浏览器就会将该字段的内容保存到本地。当下次浏览器再往该服务器发送请求时,浏览器会自动在请求头中加入 Cookie 值后再发送出去。服务器端发现浏览器发送过来的 Cookie 后,会去对比服务器上的记录,最后得到该用户的状态信息。

总结

浏览器中的 HTTP 请求从发起到结束一共经历了 8 个阶段:

  1. 构建请求
  2. 查找缓存
  3. 准备 IP 地址和端口
  4. 等待 TCP 队列
  5. 建立 TCP 连接
  6. 发起 HTTP 请求
  7. 服务器处理并响应请求
  8. 断开连接