最近在刷前端的笔试和面试题的时候,经常遇到让简述一下“从页面请求到后端响应再到页面呈现的整个过程”的问题。于是自己通过查找相关大牛的博文后,决定自己动手总结一下,以便以后复习之用。
本文总结主要借鉴自阮一峰的互联网协议入门(一)、互联网协议入门(二)、DNS 原理入门。
正文开始
其实在我看来,不管是前端开发还是后端开发的工程师都应该了解这个过程,了解这个过程可以让你整体把握整个软件的运行流程,同时可以让你更好地理解一些前后端优化、SEO,甚至一些网络安全的问题。
要想讲清楚“网络请求的整个过程”的话,其中涉及到的网络基础、HTTP协议、浏览器的工作原理等都应该是必备的知识储备,接下来的文章中,我也会在讲清楚整个请求过程的同时穿插补充这些相关知识,已经对这些知识有了解和深入研究的同学可以权当复习了。
DNS解析
当我们在客户端(浏览器)的地址栏输入一个网址并敲回车的时候,首先会执行的一步操作的就是DNS解析(也叫域名解析)。那什么是DNS解析呢?又为什么要进行DNS解析呢?带着这两个问题,我们来看看DNS解析。
DNS(域名系统)
1.DNS是什么?
DNS:Domain Name System(域名系统),互联网上作为域名和IP地址相互映射的一个分布式数据库。注意,我加粗了两个词“相互映射”和“数据库”,稍后再解释为什么要加粗它俩。
2.为什么要DNS解析?
看了DNS的概念,有些同学可能觉着更加迷惑了,不要着急,咱们从DNS解析的过程方面来更好地了解它。要讲DNS的解析过程,首先咱们得先来了解一下计算机之间是怎样进行通信的。
两台电脑之间通信
有两台电脑A和B,A电脑想向B电脑发送一条信息,那该怎么办呢?
其实很简单,就像邮递员(假设为电脑A)要给某栋大楼内的某个房间的客户(假设为电脑B)送邮件一样,邮递员要想把邮件送到客户手上,那他必须知道客户的大楼名称(或者说地址)以及客户在这栋大楼内的房间号。在互联网的世界中也是一样,电脑A想向电脑B发送一条信息,电脑A就得知道电脑B的MAC地址和IP地址。
补充1:MAC地址
以太网规定,连入网络的所有设备,都必须具有“网卡”接口。数据包必须是从一块网卡,传送到另一块网卡。网卡的地址,就是数据包的发送地址和接收地址,这叫做MAC地址。
就是说要想上网就得有块叫做“网卡”的东西,电脑的网卡很好理解,大家经常接触;而像路由器,交换机,手机,平板等联网的设备都有“网卡”这个东西。而两台设备(也可以理解为电脑)之间的通信就相当于两块网卡之间的通信,而这个网卡就是MAC地址,MAC地址就相当于“送邮件”例子中的客户房间号(啰嗦了一下,怕新手看不懂)。
而每块网卡出厂的时候,都有一个全世界独一无二的MAC地址,长度是48个二进制位,通常用12个十六进制数表示。
前6个十六进制数是厂商编号,后6个是该厂商的网卡流水号。有了MAC地址,就可以定位网卡和数据包的路径了。
至于IP地址就不用再补充了吧,既然学计算机了,肯定知道IP地址。IP地址就相当于“送邮件”例子中的大楼名称(或者说地址)。
总结:A电脑想向B电脑发送一条信息,首先A电脑要知道B电脑的MAC地址和IP地址,这其中IP地址一般是已知的,而MAC地址是未知的。这时候就需要通过ARP协议来确定B电脑的MAC地址,这其实也包括两种情况(不做详细介绍,更多了解请看阮一峰的互联网协议入门(一))。只要拿到了电脑B的IP地址和MAC地址,两台电脑就可以通信了。
域名出现
上面讲到一台电脑要想和另一台通信就需要知道另一台电脑的IP地址和MAC地址,MAC地址未知但可以通过ARP协议去获取,而IP地址是事先知道的,所以就可以通信了。但是,大家都知道IP地址这个东西是个由32位二进制组成的网络地址(IPv4),即使习惯上把它表示为四段十进制的形式(如202.201.112.232),也是不好记忆的,所以神通广大的人类就发明了域名来代替IP地址,其实就是给IP地址起了一个别名,这样就解决了IP地址不好记忆的问题了。
任何一个域名都对应一个或者多个ip地址,但是大部分都是一个域名对应一个ip地址。
DNS小结
现在咱们再来看最初的问题:
DNS:Domain Name System(域名系统),互联网上作为域名和IP地址相互映射的一个分布式数据库。
现在应该明白了吧,域名系统就是储存IP地址和域名映射的一个数据库。而DNS解析,就是通过这个数据库去查找到可以使两台联网设备进行通信的IP地址的一个过程。当然这个过程是非常的繁琐的,想继续深入研究的同学可以查看阮一峰的DNS 原理入门,现在你可以回答最初前面提到的那个问题了。
DNS是什么?
又为什么需要DNS解析?
HTTP请求
当两台联网设备通过IP地址和MAC地址完成了“链接”之后,接下来就是通信了,而通信就需要传输数据(哪怕只是一个没有数据的请求)。要想传输数据,就需要建立一个传输数据的链接(注意,我前面的链接加了引号,是因为那个时候两台电脑并为真正意义是的链接,只是找到对方了)。而这就牵扯到了另一个面试官常问的问题TCP的三次握手和TCP的四次挥手。
补充2:端口
首先来说,UDP和TCP都是传输层的协议,不同点就是传输的方式不同(简单的说,后面会详细说明他们的不同点)。
咱们在前面多次提到过通过IP地址和MAC地址可以建立两台电脑的“链接”,那么链接以后,应该怎样就行数据的传输呢?传输的数据是哪一个程序需要的呢(例如:同一台主机上有许多程序都需要用到网络,比如,你一边浏览网页,一边与朋友在线聊天。当一个数据包从互联网上发来的时候,你怎么知道,它是表示网页的内容,还是表示在线聊天的内容?)?于是人们发明了一个叫做“端口”的参数来区别不同程序之间的通信。
"端口"是0到65535之间的一个整数,正好16个二进制位。0到1023的端口被系统占用,用户只能选用大于1023的端口。不管是浏览网页还是在线聊天,应用程序会随机选用一个端口,然后与服务器的相应端口联系。
这样就可以进行数据的传输了。
UDP协议
UDP协议简单来说就是在数据包中插入一段数据用来标记端口信息,然后将数据发送出去,至于发送出去的数据包有没有被目标设备接收到,它就不管了。以这种方式发送数据包的有点就是简单,容易实现,但是缺点就是可靠性差,因为通过UDP协议发送出去的数据包无法确定发送的数据包是否到达目标设备。
TCP协议
而TCP协议就是为了解决UDP协议的缺点而诞生的,它虽然实现上比UDP协议复杂,但是可靠性好,可以保证数据被发送到目标设备上。
TCP三次握手
TCP协议是如何保证可靠性的呢?就是通过三次与目标设备的通信来确定数据包发送成功。以浏览器和服务器的通信来打比方:
浏览器:你好服务器,我是 浏览器A。
服务器:你好 浏览器A,我是 服务器B。
浏览器:服务器B 你好。
官方描述
- 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。这样就保证了,每次传送数据都会准确到达目标设备了。
TCP四次挥手
当数据包发送完毕需要断开连接的时候,就需要TCP的四次挥手来保证链接的合理断开。再次以浏览器和服务器的通信打比方:
主动结束方:你好,我的数据发送完毕了,我要进入准备断开的状态了。(此时它虽然不再发送数据了,但是可以接受数据)
另一方:我知道了,我还没有发送完毕的,你等着吧。
另一方:我也发送完毕了,可以断开链接了。(此时它也进入准备断开的状态)
主动结束方:好的,那断开吧。
官方描述
1.客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
2.服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
3.服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
4.客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。
TCP为什么建立链接是三次,关闭链接是四次呢?
这是前端面试中在设计HTTP协议问题时,经常会被问的一个问题。其实也不难理解,因为服务端的listen状态下的socket当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
通过TCP协议使得两台设备成功链接,并成功发送了数据,接下来,就需要服务器端来处理数据了。
服务器处理数据并返回响应
当服务器成功的接受到了浏览器发送的数据之后,接下来就是根据浏览器发送过来的数据就行后台程序的处理。这个过程就是在运行后端代码,当程序运行完成以后就产生了返回数据包,然后服务器端在通过TCP协议将数据包发送回浏览器。
这个过程和前面相比是不是很简单,其实不然,这个过程也相当复杂,只不过不是本文的重点就不详细介绍了,贴上一张Struts2的处理流程图,自己体会一下服务器端的某一个小阶段吧。
浏览器解析数据并呈现
当服务器返回数据包以后,接下来的工作就交给浏览器自己去处理这些数据,最后展示在页面上。这个过程涉及到了浏览器的运行原理的相关只是,本人也不是很懂,所以只是大概记录一下。
浏览器的组成
1. 用户界面:包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分。
2. 浏览器引擎:用来查询及操作渲染引擎的接口。
3. 渲染引擎:用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来。
4. 网络:用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作。
5. UI后端:用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口。
6. JS解释器:用来解释执行JS代码。
7. 数据存储:属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据,HTML5定义了web database技术,这是一种轻量级完整的客户端存储技术
渲染的流程
可以简单的描述为以下四部分:
1.解析HTML以构建DOM树
2.构建render树
3.布局render树
4.绘制render树
但实际上渲染的过程是这样的:
1.在浏览器进行渲染的时候,渲染引擎首先会解析HTML代码,然后将标签转化为DOM树上的一个个对应节点(我们可以在chorme的Elements面板中查看到)。
2.接着,渲染引擎解析外部CSS文件及style标签中的样式信息。这些样式信息以及HTML中的可见性指令将被用来构建另一棵树---render树。Render树由一些包含有颜色和大小等属性的矩形组成,它们将被按照正确的顺序显示到屏幕上。
3.Render树构建好了之后,将会执行布局过程,它将确定每个节点在屏幕上的确切坐标。
4.然后就是绘制,即遍历render树,并使用UI后端层绘制每个节点。
值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
补充WEBKIT渲染引擎和GECKO渲染引擎
总结
到这里基本上整个网络请求的过程就结束了,你在浏览器地址框输入了域名并回车,然后通过DNS解析找到相应的IP地址;然后通过HTTP协议建立了链接,找到了目标服务器的位置;接着就是TCP三次握手建立可靠链接,发送数据,服务器处理数据,TCP四次挥手断开链接;最后浏览器根据返回的数据解析渲染呈现页面。