输入网址到页面呈现的所经历的过程

1 DNS域名解析;
2 建立TCP连接;
3 发送HTTP请求;
4 服务器处理请求;
5 返回响应结果;
6 关闭TCP连接;
7 浏览器解析HTML并渲染页面;

一、DNS域名解析

当我们在浏览器地址栏上输入要访问的URL后,浏览器会分析出URL上面的域名。进入DNS解析过程:

第1步,浏览器会检查缓存中有没有这个域名对应的解析过的IP地址,如果缓存中有,这个解析过程就将结束。浏览器缓存域名也是有限制的,不仅浏览器缓存大小有限制,而且缓存的时间也有限制,通常情况下为几分钟到几小时不等,域名被缓存的时间限制可以通过TTL属性来设置。这个缓存时间太长和太短都不好,如果缓存时间太长,一旦域名被解析到的IP有变化,会导致被客户端缓存的域名无法解析到变化后的IP地址,以致该域名不能正常解析,这段时间内有可能会有一部分用户无法访问网站。如果时间设置太短,会导致用户每次访问网站都要重新解析一次域名。

第2步,如果用户的浏览器缓存中没有,浏览器会查找操作系统缓存中是否有这个域名对应的DNS解析结果。其实操作系统也会有一个域名解析的过程,在Windows中可以通过C:\Windows\System32\drivers\etc\hosts文件来设置,你可以将任何域名解析到任何能够访问的IP地址。如果你在这里指定了一个域名对应的IP地址,那么浏览器会首先使用这个IP地址。例如,我们在测试时可以将一个域名解析到一台测试服务器上,这样不用修改任何代码就能测试到单独服务器上的代码的业务逻辑是否正确。正是因为有这种本地DNS解析的规程,所以黑客就有可能通过修改你的域名解析来把特定的域名解析到它指定的IP地址上,导致这些域名被劫持。这导致早期的Windows版本中出现过很严重的问题,而且对于一般没有太多电脑知识的用户来说,出现问题后很难发现,即使发现也很难自己解决,所以Windows 7中将hosts文件设置成了只读的,防止这个文件被轻易修改。在Linux中这个配置文件是/etc/named.conf,修改这个文件可以达到同样的目的,当解析到这个配置文件中的某个域名时,操作系统会在缓存中缓存这个解析结果,缓存的时间同样是受这个域名的失效时间和缓存的空间大小控制的。

上图为以下步骤解析的过程。

第3步, 如果至此还没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不会很远,并且这台服务器的性能都很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。

第4步,如果LDNS仍然没有命中,就直接跳到Root Server 域名服务器请求解析。

第5步,根域名服务器返回给LDNS一个所查询域的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com .cn .org等)地址。

第6步,此时LDNS再发送请求给gTLD(上一步返回的)。

第7步,接受请求的gTLD查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器。

第8步,LDNS发送请求给Name Server,Name Server根据映射关系表找到目标ip,返回给LDNS。

第9步,LDNS缓存这个域名和对应的ip。

第10步,LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束。

之后浏览器根据查询到的IP地址与Web服务器进行通信,而通信的协议就是HTTP协议。

简而言之找DNS服务器的过程如下图:

浏览器客户端向本地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服务器的缓存中已有comDNS服务器的地址,因此请求根域名服务器这一步不是必需的。

 二、建立TCP链接

拿到服务器IP地址后,下一步就是连接到该服务器。对于客户端与服务器的TCP链接,必然要说的就是『三次握手』。

TCP标志位(Flags):

URG:紧急指针是否有效。为1,表示某一位需要被优先处理;
ACK:确认号是否有效,1为有效,0为无效;
PSH:提示接收端应用程序立即从TCP缓冲区把数据读走;
RST:对方要求重新建立连接,复位;
SYN:请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1;
FIN:希望断开连接;

ACK、SYN和FIN这些大写的单词表示标志位,其值要么是1,要么是0;ack、seq小写的单词表示序号。

客户端发送一个带有SYN(连接)标志的数据包给服务端,服务端收到后,回传一个带有SYN(连接)/ACK(同意)标志的数据包以示传达确认信息,最后客户端再回传一个带ACK(连接)标志的数据包,代表握手结束,连接成功。

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。

第一次握手:建立连接时,客户端发送syn包(seq=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

这些序列号可以保证数据包的有序传输
三次握手的动态过程:

 

 

 

 为什么连接建立需要三次握手,而不是两次握手? 

防止失效的连接请求报文段被服务端接收,从而产生错误。

PS:失效的连接请求:若客户端向服务端发送的连接请求丢失,客户端等待应答超时后就会再次发送连接请求,此时,上一个连接请求就是『失效的』。

若建立连接只需两次握手,客户端并没有太大的变化,仍然需要获得服务端的应答后才进入ESTABLISHED状态,而服务端在收到连接请求后就进入ESTABLISHED状态。此时如果网络拥塞,客户端发送的连接请求迟迟到不了服务端,客户端便超时重发请求,如果服务端正确接收并确认应答,双方便开始通信,通信结束后释放连接。此时,如果那个失效的连接请求抵达了服务端,由于只有两次握手,服务端收到请求就会进入ESTABLISHED状态,等待发送数据或主动发送数据。但此时的客户端早已进入CLOSED状态,服务端将会一直等待下去,这样浪费服务端连接资源。

三、发送HTTP请求

http报文结构为:

起始行:对报文进行描述;

头部:向报文中添加了一些附加信息,是一个名/只的列表,头部和协议配合工作,共同决定了客户端和服务器能做什么事情。例如:Content-Length(主体长度),Content-Type(主体类型)等;

主体:包含数据的主体部分;

与服务器建立了连接后,就可以向服务器发起请求了。这里我们先看下请求报文的结构(如下图):

post请求会把请求参数放到主体里传给后端。

四、服务器处理请求

五、返回相应结果

响应报文:

 

 

 这里起始行也包含了3个部分

  • 协议类型及版本号
  • 状态码
  • 状态码的文字描述

 

六、关闭TCP连接

TCP连接的释放一共需要四步,因此称为『四次挥手』。 
我们知道,TCP连接是双向的,因此在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接。

  • 第一次:客户端请求断开FIN,seq=u
  • 第二次:服务器确认客户端的断开请求ACK,ack=u+1,seq=v
  • 第三次:服务器请求断开FIN,seq=w,ACK,ack=u+1
  • 第四次:客户端确认服务器的断开ACK,ack=w+1,seq=u+1

为什么客户端最后要等待2MSL?

  • 客户端需要保证最后一次发送的ACK报文可以到达服务器,如果服务器未收到,可以请求客户端重发,这样客户端还有时间再发,重启2MSL计时。

为什么断开TCP连接要四次挥手?

而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

七、浏览器解析HTML并渲染页面

浏览器将域名通过网络通信从服务器拿到html文件后,如何渲染页面呢?

1.根据html文件构建DOM树和CSSOM树。构建DOM树期间,如果遇到JS,阻塞DOM树及CSSOM树的构建,优先加载JS文件,加载完毕,再继续构建DOM树及CSSOM树。

2.构建渲染树(Render Tree)。

若在构建DOM树的过程中,当 HTML 解析器遇到一个 script 标记时,即遇到了js,将立即阻塞DOM树的构建,将控制权移交给 JavaScript 引擎,等到 JavaScript 引擎运行完毕,浏览器才会从中断的地方恢复DOM树的构建。
其根本原因在于,JS会对DOM节点进行操作,浏览器无法预测未来的DOM节点的具体内容,为了防止无效操作,节省资源,只能阻塞DOM树的构建。譬如,若不阻塞DOM树的构建,若JS删除了某个DOM节点A,那么浏览器为构建此节点A花费的资源就是无效的。

若在HTML头部加载JS文件,由于JS阻塞,会推迟页面的首绘。为了加快页面渲染,一般将JS文件放到HTML底部进行加载,或是对JS文件执行async或defer加载。

构建DOM树

HTML 文档中的所有内容皆是节点,各节点之间拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成DOM树。最常见的几种节点有:文档节点、元素节点、文本节点、属性节点、注释节点

DOM节点树中节点与HTML文档中内容一一对应,DOM树构建过程:读取html文档,将字节转换成字符,确定tokens(标签),再将tokens转换成节点,以节点构建 DOM 树。如下图所示:

 

 

 

 

 

 

构建CSSOM树

CSS文档中,所有元素皆是节点,与HTML文件中的标签节点一一对应。CSS中各节点之间同样拥有层级关系,如父子关系、兄弟关系等,彼此相连,构成CSSOM树。

在构建DOM树的过程中,在 HTML 文档的 head 标签中遇到 link 标签,该标签引用了一个外部CSS样式表。由于预见到需要利用该CSS资源来渲染页面,浏览器会立即发出对该CSS资源的请求,并进行CSSDOM树的构建。

CSSOM树构建过程与DOM树构建流程一致:读取CSS文档,将字节转换成字符,确定tokens(标签),再将tokens转换成节点,以节点构建 CSSOM 树。如下图所示:

 

 

 

 

 

 

.CSS文件,又名层叠样式表。当CSSOM树生成节点时,每一个节点首先会继承其父节点的所有样式,层叠覆盖,然后再以"向下级联"的规则,为该节点应用更具体的样式,递归生成CSSOM树。譬如,上右图中第二层的p节点,有父节点body,因此该p将继承body节点的样式:"font-size: 16px;"。然后再应用该p节点自身的样式:"font-weight: bold;"。所以最终该p节点的样式为:"font-size: 16px;font-weight: bold;"。

构建渲染树

渲染树(Render Tree)由DOM树、CSSOM树合并而成,但并不是必须等DOM树及CSSOM树加载完成后才开始合并构建渲染树。三者的构建并无先后条件,亦非完全独立,而是会有交叉,并行构建。因此会形成一边加载,一边解析,一边渲染的工作现象。

构建渲染树,根据渲染树计算每个可见元素的布局,并输出到绘制流程,将像素渲染到屏幕上。

 

 

原文:

https://www.cnblogs.com/webdeve/p/7865520.html

https://zhidao.baidu.com/question/437513187.html

https://blog.csdn.net/qq_38218238/article/details/82425974

https://blog.csdn.net/aliujiujiang/article/details/81088317

https://www.cnblogs.com/chenyoumei/p/9156849.html

posted @ 2019-09-30 18:23  seeBetter  阅读(335)  评论(0编辑  收藏  举报