输入网址到页面显示 经历了什么(转载)

从前端面试题出发分析一系列知识点
大致来看,从输入url到网页显示会经历下列五个阶段

将url转换为ip地址
同服务器进行通信
获取网页内容
浏览器进行渲染
断开通信
下面来具体分析每个阶段都做了什么,因为是一道非常经典的前端面试题,并且覆盖面非常广,所以尽量做到深挖知识要点。有些可以单独写文章的地方会用黄色记号标记,之后会用文章链接替代!

#1. url到ip地址的转换 —— DNS解析
为了向www.baidu.com发送请求,必须获得www.baidu.com的ip地址,理所当然应该使用DNS去完成域名到IP地址的转换。

DNS是域名系统(Domain Name System,DNS)由分层的DNS服务器实现的分布式数据库,是一个使主机能够查询分布式数据库的应用层协议。
DNS协议运行在UDP上,使用53号端口。

浏览器会快速生成一份DNS查询报文,并封装在UDP报文的问题段中,然后进行封装成帧,以比特流的形式在物理层进行传输。

从上帝视角来看,在整个过程中首先会获取本地存储器的DNS缓存,如果有就直接使用,如果没有或是过期就会利用迭代查询的方式先向根服务器请求,根服务器会返回顶级域名.com的顶级域服务器的IP地址,再与顶级域服务器通信得到baidu.com的权威DNS服务器的IP地址,最后与权威服务器联系获得www.baidu.com的IP地址。

DNS服务器系统分为三层,第一层为根服务器,其中存储着各个顶级域服务器的相关信息;第二层为顶级域服务器,用于维护顶级域名.com、.org、.net等顶级域;第三层为权威DNS服务器,因特网上所有公共访问主机都必须由可访问的DNS记录。


#2. 和服务器建立通信 —— 三次握手
TCP协议是最重要的网络协议簇,在通信开始前,首先会进行三次握手来进行连接的建立。

TCP是传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的全双工服务(这种面向连接只是针对用户而言,其连接状态始终保持在两个端系统中,但对于下层而言,并不是电路交换网络)

第一步,客户端TCP首先向服务端的TCP发送一个特殊的报文段,该报文段的首部标志位SYN为1,又被称为SYN报文段,并随机选择一个初始序号(client_isn,其实这个序号的随机也是有一定算法的,这里不展开讨论)。
第二步,服务器收到报文后会提取SYN报文段,为TCP连接分配缓存变量,并给客户端回馈一个TCP报文段来表示允许连接,此时SYN=1,序号seq=server_isn ,以及一个ack=client_isn+1。
第三步,客户端收到报文后,为TCP连接分配缓存变量,将SYN置为0,连接正式建立。此时就可以开始正式发送数据了。在之后的每次通信中,SYN都为0。

#3. 获取网页内容 —— HTTP请求
通过http请求来获取页面内容(HTML CSS JavaScript等…),服务器接收到请求后返回客户端相对应的资源

超文本传输协议(HypeText Transfer Protocol,HTTP)是一种基于TCP协议的无状态的拉协议。一份完整的HTTP请求包含请求起始行、报文首部、报文主体三部分。分为请求报文和响应报文。
请求行包括:方法字段、URL、HTTP版本号(方法有GET / POST / HEAD / PUT / DELETE / OPTIONS / TRACE / CONNECT
响应行包括:结果状态码、原因短语、HTTP版本号(响应码:1xx信息性状态码、2xx成功状态码、3xx重定向状态码、4xx客户端错误状态码、5xx服务器错误状态码)
首部包括:时间、编码方式、语言、长度、持久连接等…
主体中填入实际内容

这里插入一部分对GET和POST方法的对比

GET方法有长度限制,POST没有
GET请求会被cache,POST不会
GET只支持url编码,POST有多种编码格式,例如text/align、from-data等
GET只能接受ASCII编码的参数,POST不是
GET会暴露参数在网址上,POST不会
GET参数通过URL传递,POST放在Request body中
GET产生一个TCP数据包;POST产生两个TCP数据包
http协议对于无状态的解决方案——cookie
服务器在响应首部加入Set-Cookie字段来附上一个标识符代表用户的状态
客户端在发送请求的时候自动附带Cookie给服务器来标识唯一用户
采用HttpOnly来阻止js脚本读取cookie从而防止xss跨站脚本攻击

HTTP协议的问题:

明文通信,可能遭到窃听
不验证通信方身份,可能遭到伪装(可能产生拒绝服务攻击DoS)
无法认证报文完整性,可能遭到篡改(中间人攻击)

HTTPS协议:

采用SSL、TSL安全套接字服务来对通信信道和内容加密
利用证书来确认通信方
采用MD5、SHA-1等散列校验方法来确认报文完整性

HTTPS相较于HTTP虽然更加安全,但是需要购买证书并且耗费一定的服务器资源

了解HTTP不同版本间差异可以看这篇文章 https://blog.csdn.net/qq_40294512/article/details/116831185


#4. 浏览器对页面进行渲染


step0.环境准备
浏览器开辟一块栈内存,用于代码执行环境;同时分配一个线程去解析代码。

当浏览器碰到link/script/img等资源请求时会开辟全新的线程去加载资源
step1.构建DOM树
当浏览器客户端从服务器那接受到HTML文档后,就会遍历文档节点然后生成DOM树,DOM树结构和HTML标签

DOM树在构建的过程中可能会被CSS和JS的加载而执行阻塞。
display:none 的元素仅仅是不展示,但是依旧会占用对应的节点DOM
注释也会在DOM树中
script标签会在DOM树中
step2.构建CSSOM树
浏览器会解析CSS文件并生成CSS规则树(CSSOM),在过程中,每个CSS文件都会被分析成StyleSheet对象,每个对象都包括CSS规则,CSS规则对象包括对应的选择器和声明对象以及其他对象。

CSS解析可以与DOM解析同进行。
CSS解析与script的执行互斥 。
在Webkit内核中进行了script执行优化,只有在JS访问CSS时才会发生互斥。
CSS选择器顺序!important > 内联样式 > ID选择器 > class选择器&伪类 > 标签选择器&伪元素选择器 > 其他选择器
css选择器渲染时从右向左,如.div a 的渲染速度比a慢
link载入是非阻塞的,@import是阻塞的
step3.构建渲染树
通过DOM树和CSS规则树,浏览器就可以通过它两构建渲染树了。浏览器会先从DOM树的根节点开始遍历每个可见节点,让后对每个可见节点找到适配的CSS样式规则并应用。

Render Tree和DOM Tree不完全对应。
display: none的元素不在Render Tree中
visibility: hidden的元素在Render Tree中
step4.渲染树布局
布局阶段会从渲染树的更节点开始遍历,由于渲染树的每个节点都是一个Render Object对象,包含宽高,位置,背景色等样式信息。所以浏览器就可以通过这些样式信息来确定每个节点对象在页面上的确切大小和位置,布局阶段的输出就是我们常说的盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。

float元素,absoulte元素,fixed元素会发生位置偏移。
我们常说的脱离文档流,其实就是脱离Render Tree。
step5.渲染树绘制
在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容。渲染树的绘制工作是由浏览器的UI后端组件完成的。

回流和重绘(reflow和repaint)
我们都知道HTML默认是流式布局的,但CSS和JS会打破这种布局,改变DOM的外观样式以及大小和位置。因此我们就需要知道两个概念:

reflow(回流):当某个部分发生了变化从而影响了布局,这个时候就需要倒回去重新渲染,这个过程叫 reflow。 常见的reflow是一些会影响页面布局的操作,诸如Tab,隐藏等。reflow 会从 html 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。

repaint(重绘): repaint则是当我们改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸和位置没有发生改变。

需要注意的是,display:none 会触发 reflow,而visibility: hidden属性则并不算是不可见属性,它的语义是隐藏元素,但元素仍然占据着布局空间,它会被渲染成一个空框,这在我们上面有提到过。所以visibility:hidden 只会触发 repaint,因为没有发生位置变化。

通常合理触发BFC来让这部分独立渲染从而减少整个页面的重绘/重构。


#5. 和服务器断开通信 —— 四次挥手
第一步,客户端TCP首先向服务端的TCP发送一个特殊的报文段,该报文段的首部标志位FIN为1,又被称为FIN报文段,并随机选择一个初始序号(client_isn)作为seq,此时客户端进入等待。
第二步,服务器收到报文后会返回一个ACK=seq+1来进行确认,从这时服务器开始处理通信关闭的相关事务,释放资源,关闭进程。
第三步,服务器完成通信关闭的相关事务时会再发送一个FIN报文,告诉客户端可以关闭。
第四步,客户端收到报文后,返回一个ACK来确认关闭,同时会等待一个RTT时间。
第五步,服务器收到返回的ACK后关闭连接,客户端在等待一个RTT后关闭连接。

这里抛出两个问题:
1.为什么握手需要三次,挥手需要四次?
2.为什么要等待一个RTT(往返时间)才关闭

其实握手也可以是四次,但是第二次和第三次请求合并起来了,但是挥手的两次请求期间需要进行资源释放等操作,所以不能合并到一起。
等待一个RTT是因为要确认服务器收到了发送到ACK,假如服务器发送的FIN报文故障或是收到的ACK未抵达,会在一个RTT后重新发送,到达时间刚好是客户端发送最后一个报文的时间+RTT,如果中间出现问题,客户端在1RTT后就会收到一个新的FIN,反之,就说明一切顺利,此时客户端关闭连接。

至此,整个流程全部结束!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_40294512/article/details/116133724

原文地址:https://www.cnblogs.com/ndh074512/p/15084028.html