本周我复习的内容:HTTP 请求生命周期
本周我复习的内容
本周我复习的内容
HTTP 请求生命周期
我最近一直在面试,正如大多数开发人员所知,面试中你可能会被问到的问题的广度和深度几乎是无法估量的。考虑到这一点,我一直在向招聘人员打探我在技术面试中可能会被问到什么问题。也许这是一个弱开发人员的标志,但我发现自己很难记住所有可能的问题类别,更不用说问题本身了。在压力下我容易忘记事情,比如|
bash 中 是进程/程序的名称,而>
通常是文件的名称。为了更好地保留信息并强迫自己写作,我决定开始发布我复习内容的演练。我往往需要至少 3 个来源才能获得对一个主题的完整、正确和写得好的解释。我想为其他人巩固这一点。
本周,我讲解了 HTTP 请求的生命周期。这是一个相当宽泛的概述,它针对的是简单的 HTTP 1.1 请求,而不是持久连接,但它可以作为 HTTP/2 和持久连接请求的一个很好的起点。我不会过多地介绍各种 HTTP 方法,因为那可以单独写一篇文章,而且它们与许多开发人员的工作流程非常接近,读者可能已经背诵过基础知识了。
步骤 1:本地处理
根据您想要了解的深度,此步骤中可能会发生很多事情,具体取决于发出请求的应用程序。我将假设此请求是由浏览器发出的,而不是 cURL、Postman 之类的 API 客户端或其他应用程序。
-
您的浏览器会提取“方案”/协议(我们已确定
为 HTTP)、主机 ( www.example.com)以及
表单中指定的可选端口号、资源路径和查询字符串<protocol>://<host><:optional port>/<path/to/resource><?query>
。例如|http|://|www.example.com||:5000||/mainpage||?query=param&query2=param2|
-
现在浏览器已经获得了请求的目标主机名,它需要解析 IP 地址1。然后,浏览器将查找自身最近请求的 URL 缓存、操作系统最近查询的缓存、路由器的缓存以及 DNS 缓存。
步骤2:解析IP
与本地完成的处理一样,从“DNS 服务器” 2解析 IP是一个包含许多步骤的序列,并且如果第一个请求未能返回地址,则包括故障转移。
-
如果缓存查找失败(我们假设失败),您的浏览器会使用UDP 3协议发起DNS 请求。该 DNS 请求的标头中包含您 DNS 服务器的预配置 IP 地址和返回 IP 地址。您尝试解析 IP 地址的主机名位于请求的“问题”部分。UDP 是一种轻量级协议,但其缺点是它不提供任何投递保证,并且除了发送和接收响应之外没有其他确认信息。
-
您的请求现在必须经过许多网络设备才能到达目标 DNS 服务器。每当数据包到达某个网络设备时,该设备都会使用路由表来确定它所连接的哪个设备最有可能位于通往目的地的最短路径上。4
-
一旦您的请求到达您配置的 DNS 服务器,该服务器就会查找与请求的主机名关联的地址。如果找到,它会发送响应。另一方面,如果您指定的 DNS 服务器找不到给定的主机名,它会将请求转发给另一个配置为延迟的 DNS 服务器。此过程会递归进行,直到找到该地址,或者找到一个“权威”的域名服务器。如果无法解析给定域名的地址,该服务器将响应失败,并且您的浏览器将返回错误。
-
不过,鉴于以上所有步骤都还只是个开始,我们假设请求成功。如果响应成功返回(记住,UDP 协议没有保证!),请求客户端现在就拥有了目标 IP。它还会收到一条包含在响应中的信息,告知其返回的响应可以缓存多长时间。这意味着后续请求可以从步骤 1.2直接到这里。
步骤3:建立TCP连接
现在客户端有了 IP 地址,它就可以发送 HTTP 5请求了,对吧?差不多了,但首先,由于请求是通过TCP 6发送的,而 TCP 6 是类似 UDP 的传输层协议,所以客户端必须打开一个 TCP 连接。
-
TCP 和 UDP 之间的一个关键区别在于,TCP 确保数据传输的交付和有序性。这大部分都非常简单,只需为每个发送的字节分配一个序列号即可。这使得接收方能够将接收到的数据包重新排序回其原始顺序,并允许发送方重新传输任何未得到接收方确认的数据包。
-
这些保证以及更多内容可以在维基百科上找到,值得一读,但最相关的是,TCP 连接是通过所谓的“三次握手”来打开的。服务器必须已经在端口上“监听”,执行被动打开,之后客户端可以发起主动打开,握手的工作原理如下:
-
现在,我们已经完成了三次握手,并建立了连接,客户端和服务器都收到了对方的连接确认。该连接还为每个通信方向(客户端->服务器,服务器->客户端)建立了一个随机的、连续的序列11,从而允许在连接上进行双向并发通信,这也称为全双工通信。
步骤 4:发送 HTTP 请求
哇,步骤好多啊!不过现在客户端有了 IP 地址和TCP 连接,终于可以发送HTTP请求了!只是……不,我开玩笑的,这次我们可以真的发送请求了!
-
请求由“请求行”、请求标头和正文组成。“请求行”只是一行,用于指示 HTTP方法、请求的资源和协议版本。请求标头由 形式的对组成
name:value <CR><LF>
。两个连续的<CR><LF>
对表示标头部分的结束。HTTP 请求中唯一必填字段是HOST
,它包含请求发送到的域和端口(domain.com:8080
),尽管在某些情况下可以省略端口。除了主机字段之外,常见的标准 HTTP 标头字段包括Origin
、Accept
、Accept-Encoding
等等。请求还可以包含任何非标准标头字段,传统上,非标准字段通过X-
在字段名称前添加前缀来表示。HTTP请求的正文内容完全是可选的,但通常包含表单数据或 JSON 之类的内容。 -
一旦 HTTP 请求被发送,它将遵循与前面讨论的类似的路由程序,不同之处在于使用 TCP 的魔术序列号功能,服务器可以确保它以正确的顺序接收整个请求。
-
服务器收到请求、处理请求并找到所请求的资源后,会生成 HTTP 响应。HTTP 响应的结构与 HTTP 请求类似,包含“状态行”、响应头字段以及可选的正文。状态行包含指示请求成功、失败或错误状态的HTTP 状态代码,以及提供详细信息的“原因消息”。
-
响应生成后,服务器将响应请求。在 TCP 层,客户端接收第一个数据包,其第一个字节应包含 HTTP 响应标头。更多数据包开始传入,并在 TCP 层根据需要重新排序。客户端在 TCP 层每收到两个数据包,就会
ACK
向服务器发送一条消息。此过程持续进行,直到响应(希望)完全加载。
步骤5:拆除和清理
我们快到了!
-
响应完全送达后,客户端会
FIN
在 TCP 层发送一个数据包,服务器会以 响应该数据包ACK
,然后通常会发送FIN
自己的 ,客户端也会以自己的ACK
信号响应该数据包。然后,客户端会等待短暂的超时时间,在此期间它无法接受新的连接,以防止先前连接的延迟数据包在端口上的后续活动期间到达。这四次握手12表示 TCP 连接的结束。 -
此时,您的浏览器开始处理收到的数据。如果收到的数据是图片、数据或其他媒体文件,并且正在被浏览器内部的某个应用程序使用,则可能会发生各种情况。如果收到的数据是 HTML,浏览器将开始解析 HTML,并渲染您请求的页面。在解析过程中,浏览器可能会遇到 HTML 之外的图片或其他媒体链接,并会针对这些内容发起新的请求,从而重新开始整个过程(尽管由于缓存的原因,通常会跳过步骤 1 和 2)。但是,考虑到我们只关注单个请求的生命周期:我们(应用程序的)工作已经完成,恭喜!
再次强调,以上所有内容仅描述了一个简单的 HTTP 事务,而非持久性事务。持久性事务会为多个请求维持相同的连接,但除了 TCP 连接建立并交换第一个控制数据包后的行为之外,该模型并没有太大差异。它也不涵盖并行 HTTP 事务,并行 HTTP 事务会在第一个请求的连接建立后为后续请求启动其他连接,但同样,其生命周期并没有太大变化。首先,这些其他方法有助于缓解您在阅读时可能注意到的一个问题:单个 TCP 连接的握手启动和拆除过程可能非常耗时,而开发人员可以避免重复执行这些过程或连续执行这些过程。
好了,就是这样,这就是单个 HTTP 请求的多层生命周期!感谢您的阅读,请告诉我您的想法,如果您觉得有任何需要修改的地方,请随时联系我们!
资料来源: |
---|
Quora:一般步骤 |
维基百科:HTTP 会话 |
维基百科:URL、URI 和 URN |
维基百科:权威域名服务器 |
维基百科:HTTP |
HTTP 请求的图像来源:TheJosh 作品,公共领域 |
TCP 握手 |
维基百科:TCP 协议操作 |
维基百科:全双工通信 |
一般步骤 |
TCP 启动和关闭的实时步骤 |
OSI 层 |
HTTP 常规步骤 |
-
对于外行人来说,互联网协议地址 ( IP Address) 是连接到TCP/IP 网络的计算机、服务器或其他资源的数字标识符。如果您从未见过这些术语,我建议您在继续阅读之前先阅读一篇关于互联网工作原理的入门知识,因为这篇文章只是对其中一部分内容的分析 。↩
-
这是一个提供主机名及其相关 IP 集合的服务器 。↩
-
如果请求或响应大于单个数据包的大小,浏览器将改用 TCP 请求。IPv6 和 DNSSEC 响应将会发生这种情况。UDP 是一种轻量级协议,它优化了速度,但其缺点是无法保证传输的正确性和顺序性。它非常适合在网络接口之外进行错误校验,并且宁愿丢包也不愿延迟传输的用例。UDP 无需握手,因此除了发送和接收响应之外,没有其他确认信息 。↩
-
感谢Quora 上的EO Stinson,他是我唯一能找到的提及此事的来源。他的许多回答都为我的笔记提供了素材 。↩
-
HTTP(超文本传输协议)是一种“应用层协议” ,通常假设使用 TCP 作为其“传输层协议”(尽管有些实现可以使用 UDP 等协议)。我们不会过多地探讨这意味着什么,但最好理解,当我们讨论 HTTP 时发生的一切通常都发生在我们之前讨论的层之上,这意味着我们可以将更多事情视为理所当然 。↩
-
TCP(传输控制协议) ↩
-
代表“同步” ↩
-
这是一个不包含请求/响应特定信息的数据包,仅用于管理事务 ↩
-
代表“同步确认” ↩
-
我猜他们在起名字的时候懒了 :D ↩
-
也称为连接参数 ↩
-
虽然实现方式各有不同,但可以概括为 3 个步骤 ↩