从输入URL到页面展示的过程
- 1、输入网址
- 2、DNS解析
- 3、建立tcp连接
- 4、客户端发送HTPP请求
- 5、服务器处理请求
- 6、服务器响应请求
- 7、浏览器展示HTML
- 8、浏览器发送请求获取其他在HTML中的资源。
1.浏览器解析url
当开始在浏览器中输入网址的时候,浏览器其实就已经在智能的匹配可能得 url 了,他会从历史记录,书签等地方,找到已经输入的字符串可能对应的 url,然后给出智能提示,让你可以补全url地址。对于 google的chrome 的浏览器,他甚至会直接从缓存中把网页展示出来,就是说,你还没有按下 enter,页面就出来了。
2、浏览器查找域名的 IP 地址
1、请求一旦发起,浏览器首先要做的事情就是解析这个域名,一般来说,浏览器会首先查看本地硬盘的 hosts 文件,看看其中有没有和这个域名对应的规则,如果有的话就直接使用 hosts 文件里面的 ip 地址。
2、如果在本地的 hosts 文件没有能够找到对应的 ip 地址,浏览器会发出一个 DNS请求到本地DNS服务器 。本地DNS服务器一般都是你的网络接入服务器商提供,比如中国电信,中国移动。
3、查询你输入的网址的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果,此过程是递归的方式进行查询。如果没有,本地DNS服务器还要向DNS根服务器进行查询。
4、根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。这种过程是迭代的过程。
5、本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。
6、最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。
1)什么是DNS?
DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。
通俗的讲,我们更习惯于记住一个网站的名字,比如www.baidu.com,而不是记住它的ip地址,比如:167.23.10.2。而计算机更擅长记住网站的ip地址,而不是像www.baidu.com等链接。因为,DNS就相当于一个电话本,比如你要找www.baidu.com这个域名,那我翻一翻我的电话本,我就知道,哦,它的电话(ip)是167.23.10.2。
2)DNS查询的两种方式:递归查询和迭代查询
1、递归解析
当局部DNS服务器自己不能回答客户机的*DNS查询时,它就需要向其他DNS服务器进行查询。此时有两种方式,如图*所示的是递归方式。局部DNS服务器自己负责向其他DNS服务器进行查询,一般是先向该域名的根域服务器查询,再由根域名服务器一级级向下查询。最后得到的查询结果返回给局部DNS服务器,再由局部DNS服务器返回给客户端。
2、迭代解析
当局部DNS服务器自己不能回答客户机的DNS查询时,也可以通过迭代查询的方式进行解析,局部DNS服务器不是自己向其他*DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端*DNS程序,客户端*DNS程序再继续向这些*DNS服务器进行查询,直到得到查询结果为止。也就是说,迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。比如说:baidu.com的服务器ip地址在192.168.4.5这里,你自己去查吧,本人比较忙,只能帮你到这里了。
step2:DNS域名解析
浏览器理解用户输入的信息,知道用户想要用http访问一个网络地址是“www.ruanyifeng.com”的网站。那么如何找到这个地址呢,就像你打的回家,你跟司机说去阮老师家,他哪儿知道阮老师家是哪里呢?你得告诉他门牌号呀。网站服务器的门牌号就是IP地址。所有浏览器首先要确认的是域名所对应的服务器在哪里。将域名解析成对应的服务器IP地址这项工作,是由DNS服务器来完成的。 客户端收到你输入的域名地址后,它首先去找本地的hosts文件,检查在该文件中是否有相应的域名、IP对应关系,如果有,则向其IP地址发送请求,如果没有,再去找DNS服务器。一般用户很少去编辑修改hosts文件。 DNS服务器层级如下:
DNS查询的具体步骤如下:
-
从浏览器缓存中查询。浏览器会存储一定时间的DNS记录,操作系统不会告诉浏览器每个DNS记录的保存时限,不同浏览器设置保存时限为一个固定值(不同浏览器情况不同,一般在2-30分钟)。
-
从操作系统缓存中查询。如果浏览器中没有包含想要的缓存记录,那浏览器就会发起操作系统请求,继续查询操作系统缓存
-
从路由器中查询DNS缓存。请求持续发送到你的路由,它通常会有自己的DNS缓存。
-
从ISP中查询DNS缓存。下一个被查询地方是ISP缓存DNS的服务器。
-
域名服务器迭代查询,根据返回的地址逐级向上查询。首先从root域名服务器中查询如.com域名服务器,然后逐步向前查询,.com顶级域名服务器到ruanyifeng的域名服务器。一般来说,.com级别的都已经在缓存中了,所以一般不会进行对root域名服务器的查询。下面给出一张迭代查询的图。
浏览器客户端向本地DNS服务器发送一个含有域名www.cnblogs.com的DNS查询报文。本地DNS服务器把查询报文转发到根DNS服务器,根DNS服务器注意到其com后缀,于是向本地DNS服务器返回comDNS服务器的IP地址。本地DNS服务器再次向comDNS服务器发送查询请求,comDNS服务器注意到其www.cnblogs.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应。最后,本地DNS服务器将含有www.cnblogs.com的IP地址的响应报文发送给客户端。 从客户端到本地服务器属于递归查询,而DNS服务器之间的交互属于迭代查询。 正常情况下,本地DNS服务器的缓存中已有comDNS服务器的地址,因此请求根域名服务器这一步不是必需的。
step3:浏览器获取端口号
好了,阮老师家的门牌号知道了,正常来讲是可以出发了。可是对于网络有些不一样,你还需要指定端口号。端口号之于计算机就像窗口号之于银行,一家银行有多个窗口,每个窗口都有个号码,不同窗口可以负责不同的服务。端口只是一个逻辑概念,和计算机硬件没有关系。现在可以这么说,阮老师家好几扇们,办不同的业务走不同的门,你得告诉师傅你走那扇门,你要不说,就默认你是个普通客人,丢大门得了。http协议默认端口号是80。
step4:TCP建立连接
好了,IP和端口都有了,能出发了么?师傅很热心,怕你去了对方家里没人啊,于是根据查到的信息给对方家里打了电话 师傅:“喂,家里有人没啊?有客人来拜访啊?” 对方:“有啊,来吧” 师傅:“好嘞”。 在http消息发送前,需要建立客户端与服务器的TCP链接,也就是进行所谓的三次握手。 TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接,TCP使用的流量控制协议是可变大小的滑动窗口协议。
TCP三次握手的过程如下:
- 客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
- 服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
- 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。
step5: 发送HTTP请求
你们和阮老师家里互相确定了到访的事情后,你们终于开心地出发了。也就是说,与服务器建立了连接后,就可以向服务器发起请求了。这里我们先看下请求报文的结构:
我们在chrome浏览器查看报文首部信息:
step6:服务器处理请求
好了,终于到了阮老师家,坐车去阮老师家的例子到此就结束了。不过我们的渲染页面的目的还没达到,现在请求只是成功达到了服务器,接下来服务器需要响应浏览器的请求。 服务器端收到请求后的由web服务器(准确说应该是http服务器)处理请求,诸如Apache、Ngnix、IIS等。web服务器解析用户请求,知道了需要调度哪些资源文件,再通过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果通过web服务器返回给浏览器客户端。下面以静态渲染的页面为例,ajax渲染不需要在服务器做页面数据写入。
step7:返回响应结果
在HTTP里,有请求就会有响应,哪怕是错误信息。这里我们同样看下响应报文的组成结构:
在响应结果中都会有个一个HTTP状态码,比如我们熟知的200、301、404、500等。通过这个状态码我们可以知道服务器端的处理是否正常,并能了解具体的错误。 状态码由3位数字和原因短语组成。根据首位数字,状态码可以分为五类:
另外还有一些其他信息(chrome中显示的response headers如下):
内容编码头部告诉浏览器响应体使用了gzip压缩算法,解压后就会看到你期望的HTML了。
除了压缩信息之外,头部还详细说明了是否和怎么缓存页面、设置cookies(在这个响应中没有)、隐秘信息等
或许有人注意到了设置了内容类型为text/html,这部分头部说明了浏览器将响应内容作为HTML渲染,而不是作为文件下载。浏览器将使用头部决定如何解释响应结果,当然也会考虑其他因素,比如URL的扩展情况。
step8: 关闭TCP连接
为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。 建立一个连接需要三次握手,而终止一个连接要经过四次挥手,这是由TCP的半关闭(half-close)造成的。具体过程如下图所示。
(1) 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。 (2) 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。 注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。 (3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。 (4) 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
注意:
(1) “通常”是指,某些情况下,步骤1的FIN随数据一起发送,另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端,有可能被合并成一个分节。[2]
(2) 在步骤2与步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为“半关闭”(half-close)。
(3) 当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一个终止本进程的信号)终止时,所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN。
无论是客户还是服务器,任何一端都可以执行主动关闭。通常情况是,客户执行主动关闭,但是某些协议,例如,HTTP/1.0却由服务器执行主动关闭。
step9:浏览器加载解析渲染
当浏览器获得一个html文件时,会“自上而下”加载,并在加载过程中进行解析渲染。 解析:
- 浏览器会将HTML解析成一个DOM树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
- 将CSS解析成 CSS Rule Tree 。
- 根据DOM树和CSSOM来构造 Rendering Tree。注意:Rendering Tree 渲染树并不等同于 DOM 树,因为一些像 Header 或 display:none 的东西就没必要放在渲染树中了。
这一块的过程比较复杂,会开单章。
step10:浏览器发送嵌入在HTML中的对象的请求
随着浏览器渲染HTML,浏览器会注意到有些标签需要请求其他URLs的资源,浏览器将会发送一个GET请求来重新获取每个文件 。比如js文件,css文件,图片资源等。 每个URLs会像获取HTML页面的过程一样获取相应资源。所以,浏览器会在DNS中查询域名,并向URL发送请求,进行重定向(其实以上步骤我是省略了重定向这一步的)等等以上步骤
当然,静态文件和动态网站不一样,它们允许被浏览器缓存。一些文件可能会根本不经过服务器,直接被从缓存中取出。因为响应结果中返回一个包含着Expires头的文件,所以浏览器知道要缓存一个文件多久。另外每个响应可能包含着ETag头,其作用类似版本号,如果浏览器发现已经拥有了一个文件的ETag,那么就会立即停止此文件传输。