输入一个URL之后到页面加载的整个过程分析

URL------>页面加载

我们经常在各大浏览器上面输入一个想要查看的网址(URL),立马就能在页面上看到相关信息,
那么这个过程是怎么实现的呢,下面具体分析一下这一整个过程。

总的来说分为以下几个过程:
1、DNS解析
2、建立TCP连接
3、发送HTTP请求
4、接收处理请求,服务器进行处理并返回HTTP报文
5、浏览器解析并渲染页面
6、关闭连接

1、DNS解析

DNS( Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工作。DNS就是这样的一位“翻译官”,它的基本工作原理可用下图来表示
输入一个URL之后到页面加载的整个过程分析
综上所述:
DNS解析的过程就是寻找哪台机器上有你需要资源的过程。当你在浏览器中输入一个地址时,例如www.baidu.com,其实不是百度网站真正意义上的地址。互联网上每一台计算机的唯一标识是它的IP地址,但是IP地址并不方便记忆。用户更喜欢用方便记忆的网址去寻找互联网上的其它计算机,也就是上面提到的百度的网址。所以互联网设计者需要在用户的方便性与可用性方面做一个权衡,这个权衡就是一个网址到IP地址的转换,这个过程就是DNS解析。它实际上充当了一个翻译的角色,实现了网址到IP地址的转换。

解析过程分析图:
输入一个URL之后到页面加载的整个过程分析
本地域名服务器:本地DNS一般是指你电脑上网时IPv4或者IPv6设置中填写的那个DNS。这个有可能是手工指定的或者是DHCP自动分配的。

如果你的电脑是直接连的运营商网络,一般默认设置情况下DNS为DHCP分配到的运营商的服务器地址。
如果你的电脑和运营商之间还存在无线或者有线路由,那有可能路由器本身还内置了一个DNS转发器,作用是将发往它所有的DNS请求转发到上层DNS。此时由于路由器本身也接管了下挂电脑的DHCP服务,所以它分配给下面电脑的DNS地址就是它自身,所以你能看到电脑的DNS分配到的可能是192.168.1.1。实际上就是路由器自身,而路由器的DNS转发器将请求转发到上层ISP的DNS。所以这里说DNS是局域网或者是运营商的都可以。

根域名服务器:根服务器主要用来管理互联网的主目录,全世界IPv4根服务器只有13台(这13台IPv4根域名服务器名字分别为“A”至“M”),1个为主根服务器在美国。其余12个均为辅根服务器,其中9个在美国,欧洲2个,位于英国和瑞典,亚洲1个位于日本。

全球有那么多的计算机,要让一台服务器记录所有的域名和IP的对应关系的数据库,那这台服务器肯定要炸了,因此人们想到了将这些庞大的数据库分布式地存储于不同的计算机中,让他们共同提供查询域名和IP的功能,所以分布式存储在上面说到的13个根服务器中

*域名服务器:用来指示某个国家/地区或组织使用的名称和类型名称,一般有.com.net等等。

上述图片是查找www.google.com的IP地址过程。首先在本地域名服务器中查询IP地址,如果没有找到,本地域名服务器会向根域名服务器发送一个请求,如果根域名服务器也不存在该域名时,本地域名会向com*域名服务器发送一个请求,依次类推下去。直到最后本地域名服务器得到google的IP地址并把它缓存到本地,供下次查询使用。

从上述过程中,可以看出网址的解析是一个从右向左的过程: com -> google.com -> www.google.com。但是你是否发现少了点什么,根域名服务器的解析过程呢?事实上,真正的网址是www.google.com.,并不是我多打了一个.,这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,既然是默认情况下,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上,所有网址真正的解析过程为:. -> .com -> google.com. -> www.google.com.

分析图
输入一个URL之后到页面加载的整个过程分析
上图查找IP一共经历了8个过程,试想一下,如果我们每次取查找一个IP地址都要耗时这么久吗,是不是太浪费时间了,所以就提出了一个DNS缓存机制的思想。

DNS缓存

DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,*域名服务器缓存,主域名服务器缓存。

DNS缓存的概念:当一个DNS服务器查询到域名和IP的映射关系后,会将该映射数据写入自己的缓存中,如果其他的主机再来询问相同的映射关系时,直接读取自己的缓存,而不需要再去询问其他服务器了。

DNS中的TCP和UDP
DNS是同时监听TCP和UDP的53号端口,那么DNS什么时候使用UDP,什么时候使用TCP呢?
DNS在大部分情况下是使用UDP的,但是UDP能够传输的DNS报文最大是512字节,如果客户端在得到响应报文后得知该响应报文不止512字节的时候,客户端会重新使用TCP发送请求报文,DNS服务器使用TCP将大于512字节的报文分段传输,这是其中一种使用TCP的情况;
另外一种使用TCP的情况是,主从DNS服务器在进行数据库同步时,那么庞大的数据量,slave是怎么从master哪里更新的,当然使用的是TCP分段传输了。

DNS负载均衡

不知道大家有没有思考过一个问题: DNS返回的IP地址是否每次都一样?如果每次都一样是否说明你请求的资源都位于同一台机器上面,那么这台机器需要多高的性能和储存才能满足亿万请求呢?其实真实的互联网世界背后存在成千上百台服务器,大型的网站甚至更多。但是在用户的眼中,它需要的只是处理他的请求,哪台机器处理请求并不重要。DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡,又叫做DNS重定向。大家耳熟能详的CDN(Content Delivery Network)就是利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容。

2、建立TCP连接

参考之前写的博客:TCP连接

3、发送HTTP请求

发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口(HTTP协议80/8080, HTTPS协议443)。HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文。

请求行
格式如下:
Method Request-URL HTTP-Version CRLF

eg: GET index.html HTTP/1.1
常用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD。

请求报头
请求报头允许客户端向服务器传递请求的附加信息和客户端自身的信息。
PS: 客户端不一定特指浏览器,有时候也可使用Linux下的CURL命令以及HTTP客户端测试工具等。
常见的请求报头有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。

请求正文
当使用POST, PUT等方法时,通常需要客户端向服务器传递数据。这些数据就储存在请求正文中。在请求包头中有一些与请求正文相关的信息,例如: 现在的Web应用通常采用Rest架构,请求的数据格式一般为json。这时就需要设置Content-Type: application/json。

4、接收处理请求,服务器进行处理并返回HTTP报文

从在固定的端口接收到TCP报文开始,这一部分对应于编程语言中的socket。它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。这一部分工作一般是由Web服务器去进行,Web服务器有Tomcat, Jetty和Netty等等。

HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文。

状态码
状态码是由3位数组成,第一个数字定义了响应的类别,且有五种可能取值:

1xx:指示信息–表示请求已接收,继续处理。

2xx:成功–表示请求已被成功接收、理解、接受。

3xx:重定向–要完成请求必须进行更进一步的操作。

4xx:客户端错误–请求有语法错误或请求无法实现。

5xx:服务器端错误–服务器未能实现合法的请求。

响应报头
常见的响应报头字段有: Server, Connection…

响应报文
服务器返回给浏览器的文本信息,通常HTML, CSS, JS, 图片等文件就放在这一部分。

5、浏览器解析并渲染页面

浏览器在收到HTML,CSS,JS文件后,它是如何把页面呈现到屏幕上的?下图对应的就是WebKit渲染的过程。
输入一个URL之后到页面加载的整个过程分析
浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;当盒模型的位置,大小以及其他属性,如颜色,字体,等确定下来之后,浏览器便开始绘制内容,这个过程称为repain。页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。

JS的解析是由浏览器中的JS解析引擎完成的。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。

浏览器在解析过程中,如果遇到请求外部资源时,如图像,iconfont,JS等。浏览器将重复1-6过程下载该资源。请求过程是异步的,并不会影响HTML文档进行加载,但是当文档加载过程中遇到JS文件,HTML文档会挂起渲染过程,不仅要等到文档中JS文件加载完毕还要等待解析执行完毕,才会继续HTML的渲染过程。原因是因为JS有可能修改DOM结构,这就意味着JS执行完成前,后续所有资源的下载是没有必要的,这就是JS阻塞后续资源下载的根本原因。CSS文件的加载不影响JS文件的加载,但是却影响JS文件的执行。JS代码执行前浏览器必须保证CSS文件已经下载并加载完毕。

6、关闭连接

参考博客:TCP四次挥手过程关闭连接