HTTP 请求流程

2023/2/1 browserhttp

# HTTP 请求流程

HTTP 协议,正是建立在 TCP 连接基础之上的。HTTP 是一种允许浏览器向服务器获取资源的协议,是 Web 的基础,通常由浏览器发起请求,用来获取不同类型的文件,例如 HTML 文件、CSS 文件、JavaScript 文件、图片、视频等。

输入 URL 之后,浏览器会完成哪些动作呢?

  1. 构建请求

浏览器构建请求行信息(如下所示),构建好后,浏览器准备发起网络请求。

GET /index.html HTTP1.1
  1. 查找缓存

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

  1. 准备 IP 地址和端口

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

  1. 等待 TCP 队列

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

  1. 建立 TCP 连接

通过三次握手建立连接。

  1. 发送 HTTP 请求

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

发送请求行,就是告诉服务器浏览器需要什么资源,最常用的请求方法是 Get。另外一个常用的请求方法是 POST,它用于发送一些数据给服务器,比如登录一个网站,就需要通过 POST 方法把用户信息发送给服务器。如果使用 POST 方法,那么浏览器还要准备数据给服务器,这里准备的数据是通过请求体来发送。

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

# 服务器端处理 HTTP 请求流程

  1. 返回请求

首先服务器会返回响应行,包括协议版本和状态码。

随后,服务器会随同响应向浏览器发送响应头。响应头包含了服务器自身的一些信息,比如服务器生成返回数据的时间、返回的数据类型(JSON、HTML、流媒体等类型),以及服务器要在客户端保存的 Cookie 等信息。

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

  1. 断开连接

通常情况下,一旦服务器向客户端返回了请求数据,它就要关闭 TCP 连接。如果浏览器或者服务器在其头信息中加入了 Connection:Keep-Alive,那么 TCP 连接在发送后将仍然保持打开状态,这样浏览器就可以继续通过同一个 TCP 连接发送请求。保持 TCP 连接可以省去下次请求时需要建立连接的时间,提升资源加载速度。比如,一个 Web 页面中内嵌的图片就都来自同一个 Web 站点,如果初始化了一个持久连接,你就可以复用该连接,以请求其他资源,而不需要重新再建立新的 TCP 连接。

# 重定向

响应行返回的状态码是 301,状态 301 就是告诉浏览器,我需要重定向到另外一个网址,而需要重定向的网址正是包含在响应头Location 字段中,接下来,浏览器获取 Location 字段中的地址,并使用该地址重新导航,这就是一个完整重定向的执行流程。

# 为什么很多站点第二次打开会很快?

主要原因是第一次加载页面过程中,缓存了一些耗时的数据。包括 DNS 缓存和页面资源缓存。

当服务器返回 HTTP 响应头给浏览器时,浏览器是通过响应头中的 Cache-Control 字段来设置是否缓存该资源。通常,我们还需要为这个资源设置一个缓存过期时长,而这个时长是通过 Cache-Control 中的 Max-age 参数来设置的。

如果缓存过期了,浏览器则会继续发起网络请求,并且在 HTTP 请求头中带上 If-None-Match,服务器会根据 If-None-Match 的值来判断请求的资源是否有更新。如果有更新,服务器直接返回最新的资源个浏览器;如果没有更新,返回状态码 304。

# 如何保持登录状态?

  • 用户打开登录页面,在登录框里输入用户名和密码,点击确定按钮。点击按钮会触发页面脚本生成用户登录信息,然后调用 POST 方法提交用户登录信息给服务器。

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

Set-Cookie: UID=3431uad;
  • 浏览器在接收到服务器的响应头后,开始解析响应头,如果遇到响应头里含有 Set-Cookie 字段,浏览器就会把这个字段信息保存到本地。比如把 UID=3431uad 保存到本地。

  • 当用户再次访问时,浏览器会发起 HTTP 请求,但在发起请求之前,浏览器会读取之前保存的 Cookie 数据,并把数据写进请求头里的 Cookie 字段里,然后浏览器再将请求头发送给服务器。

  • 服务器在收到 HTTP 请求头数据之后,就会查找请求头里面的 Cookie 字段信息,当查找到包含 UID=3431uad 的信息时,服务器查询后台,并判断该用户是已登录状态,然后生成含有该用户信息的页面数据,并把生成的数据发送给浏览器。

  • 浏览器在接收到该含有当前用户的页面数据后,就可以正确展示用户登录的状态信息了。

    我记得
    赵雷