完整的一次 HTTP 请求响应过程

因特网无疑是人类有史以来最伟大的设计,它互联了全球数亿台计算机、通讯设备,即便位于地球两端的用户也可在顷刻间完成通讯。
可以说『协议』是支撑这么一个庞大而复杂的系统有条不紊运作的核心,而所谓『协议』就是通讯双方所必须遵守的规则,在这种规则下,不同的数据报可能被解析为不同的响应动作。
简而言之,『协议』就是指如果发送和接收方按照这个规则进行数据报文的发送,即可在基本的数据传输之上得到某些特殊的功能或服务,否则你的数据别人是不认识的。例如:遵循 TCP 协议的两端,可以在不可靠的网络传输中得到可靠的数据传输能力。
整个计算机网络是分层的,有七层模型,也有五层模型,个人觉得五层模型更利于理解。我们从上至下的介绍这五个层,它们分别是,应用层,运输层,网络层,数据链路层和物理层。
应用层
『应用层』算是距离用户最近的一层了,主机上的一个个的进程就构成了『应用层』。比如你在你的浏览器地址栏输入了 「www.baidu.com」,你的浏览器在应用层会做哪些事情呢?
首先浏览器会使用 DNS 协议返回域名「www.baidu.com」所对应的 IP 地址,关于 DNS 我们待会详细介绍。
接着,应用层决定创建一个『TCP 套接字』,然后将这个请求动作封装成一个 Http 数据报并推入套接字中。
套接字分为两种类型,『TCP 套接字』和『UDP 套接字』,应用层同时可能会有几十个数据报的发出,而运输层也会收到所有的响应报文,那么它该如何区分这些报文到底是谁的响应报文呢?
而套接字就是用于区分各个应用层应用的,往往由端口号和 IP 地址进行标识,运输层只要查看响应报文的源端口号和 IP 地址就能够知道该将报文推送给哪个套接字了。
当一个应用层数据报被推动进套接字之后,应用层的所有工作也算是全部完成了,关于后续报文的去向,它已经不用管了。
这里还要说明一点的是,『TCP 套接字』和『UDP 套接字』两者本质上的区别在于,前者保证数据报可靠地到达目的地,但是必然耗时,而后者不保证数据报一定能到达目的地,但是速度快,这也是应用层协议在选择运输层协议的时候需要考虑的一点。
关于 TCP 和 UDP,我们后续还会继续说,下面我们看看域名解析协议 DNS 是如何运作的,它是如何将一个域名解析返回它的 IP 地址的。
DNS 原理
首先明确一点的是,DNS 是一个应用层协议,并且它选择的运输层协议是 UDP,所以你的域名解析过程一般会很快,但也会经常出现解析失败的情况,然而刷新一下又好了
完整的一次 HTTP 请求响应过程
在 DNS 服务器上,域名和它所对应的 IP 地址存储为一条记录,而所有的记录都不可能只存储在一台服务器上,我相信无论多么强大的服务器都扛不住全球上亿次的并发量吧。
大致来说,有三种类型的 DNS 服务器,根 DNS 服务器,*域 DNS 服务器和权威 DNS 服务器。
其中,*域 DNS 服务器主要负责诸如 com、org、net、edu、gov 等*域名。
根 DNS 服务器存储了所有*域 DNS 服务器的 IP 地址,也就是说你可以通过根服务器找到*域服务器。例如:「www.baidu.com」,根服务器会返回所有维护 com 这个*域服务器的 IP 地址。
然后你任意选择其中一个*域服务器,请求该*域服务器,该*域服务器拿到域名后应当能够做出判断并给出负责当前域的权威服务器地址,以百度为例的话,*域服务器将返回所有负责 baidu 这个域的权威服务器地址。
于是你可以任意选择其中一个权威服务器地址,向它继续查询 「www.baidu.com」 的具体 IP 地址,最终权威服务器会返回给你具体的 IP 地址。
至此,我们简单描述了一个域名解析的大致过程,还有一些细节之处并未提及,我们等会会通过一个实例来完整的看一下,下面描述一个非常重要的概念。
整个 DNS 解析过程中,有一个非常核心的人物我们一直没介绍它,它就像主机的『助理』一样,帮助主机查询域名的 IP 地址。它叫做『本地 DNS 服务器』。

完整的一次 HTTP 请求响应过程
大家每次通过 DHCP 动态获取 IP 地址的时候,这一点后文会说。其实路由器不仅给你返回了 IP 地址,还会告诉你一个 DNS 服务器地址,这个就是你的本地 DNS 服务器地址,也就是说,你的所有域名解析请求只要告诉它就行了,它会帮你查并返回结果给你的。
除此之外,本地 DNS 服务器往往是具有缓存功能的,通常两天内的记录都会被缓存,所以大部分时候你是感觉不到域名解析过程的,因为往往就是从缓存里拿的,非常快。
下面我们看一个简单的案例:
网上找的一个图,自己画实在太费时间了,但足以说明问题,现在假设请求 「www.xx.com」
完整的一次 HTTP 请求响应过程
①:主机向负责自己的本地 DNS 发送查询报文,如果本地服务器缓存中有,将直接返回结果
②:本地服务器发现缓存中没有,于是从内置在内部的根服务器列表中选一个发送查询报文
③:根服务器解析一下后缀名,告诉本地服务器负责 .com 的所有*服务器列表
④:本地服务器选择一个*域服务器继续查询,.com 域服务器拿到域名后继续解析,返回负责 .xx 域的所有权威服务器列表
⑥:本地服务器从返回的权威服务器之一再次发送查询报文,最终会从某一个权威服务器上得到具体的 IP 地址
⑧:向主机返回结果

其实整个 DNS 报文的发送与响应过程都是要走我们的五层协议的,只是这里重点在于理解 DNS 协议本身,所以并未提及其他层的具体细节,这里的强调是提醒你 DNS 只是一个应用层协议。
运输层
运输层的任务就是将应用层推出套接字的所有数据报收集起来,并且按照应用层指定的运输层协议,TCP 或 UDP,重新封装应用层数据报,并推给网络层等待发送。
TCP 和 UDP 是运输层的两个协议,前者是基于连接的可靠传输协议,后者是无连接的不可靠传输协议,所以前者更适合于一些对数据完整性要求高的场合,后者则适合于那种可以允许数据丢失但对传输速率要求特别高的场景,例如:语音电话,视频等,丢一两个包最多卡顿一下,无伤大雅。
UDP
UDP 不同于 TCP 那样复杂,它既不保证数据可靠的传输到目的地,也不保证数据按序到达目的地,仅仅提供了简单的差错检验。报文格式如下:
完整的一次 HTTP 请求响应过程
其中,数据就是应用层推出来的数据,源端口号用于响应报文的交付,目的端口号用于向目的进程交付数据,校验和用于检查传输过程中数据是否受损,如果受损,UDP 将直接丢弃该报文。
TCP
TCP 要稍微复杂些,它是面向连接的,并且基于连接提供了可靠的数据传输服务,它的数据报文格式如下:
完整的一次 HTTP 请求响应过程
作者:YangAM
链接:https://juejin.im/post/5b10be81518825139e0d8160
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。