这是我参与更文挑战的第13天,活动详情查看: 更文挑战
写在前面
自己之前刷过一些面经,经常有个很高频的面试题出现,那就是页面从输入URL到渲染都发生了什么
,自己也看过很多答案,但是过段时间很容易就忘了,这次把它记录成文章,加深自己印象,也方便下次查阅。这里面涉及的知识点时很多,如果能完整了解这个过程,对以后的问题的排查,性能优化都是有很大帮助。
页面从输入URL到渲染都发生了什么
简单的概括,可以分为以下几个过程:
- DNS解析
- TCP连接
- 发送HTTP请求
- 服务器处理请求并返回结果
- 浏览器解析并渲染页面
DNS解析
DNS
,全称是(Domain Name System,域名系统),因为服务器的ip是一串数字,不好记,于是便用域名代替ip,比较有语义,好记。 比如掘金主页(https://juejin.cn
),头条主页(https://toutiao.com
)。
什么是DNS解析
?就是解析域名然后获取到对应的ip,流程是
- 首先先找浏览器有没有dns缓存(之前有访问记录),如果有则返回ip
- 如果没有,则寻找本地的host文件,看看有没有域名记录,如果有则返回ip
- 如果本地host文件没有则直接向本地DNS服务器请求,如果还是没有,继续向上DNS服务器请求,直至返回;
TCP连接
浏览器拿到ip后,在向服务器发送http请求之前,先要和服务器建立TCP连接;
怎么建立TCP连接?答:三次握手
过程如下:
- 第一次握手: 客户端发送
SYN
数据包给服务端 - 第二次握手: 服务端收到客户端的数据包,返回
SYN/ACK
数据包给客户端 - 第三次握手: 客户端收到服务端的返回后,发送
ACK
数据包给服务端
连接建立成功,正式开始传送数据
两次握手可不可以? 不可以,TCP是可靠的,要保持可靠至少要三次握手
我举个例子,假设2个不认识的人A与B在两栋楼楼顶交流,能听到但是互相看不见:
A:你好,我叫答案,你叫什么名字? (第一次握手)
B:你好,我叫cp3,很高兴认识你,你真帅! (第二次握手)
A: 谢谢! (第三次握手)
…然后继续愉快聊下去
但是如果只是两次握手,那么就会有可能出现:
A第一次介绍后,B听到后,两次握手建立连接,但是这时候B由于声音小,风大,导致A收不到B的反馈,A独自下楼了,但是B不知道,还在等待A的回馈,导致B一直在等待中,可惜了~
透过这个简单的例子,两次握手是有可能不可靠的
建立连接后怎么断开TCP连接? 答: 四次挥手
过程如下:
- 第一次挥手:客户端向服务端发出一个
FIN
,用来关闭连接,此时客户端还能接收数据; - 第二次挥手:服务端在收到这个信号之后会向客户端发出一个
ACK
,然后服务端就进入了close_wait
(关闭等待)状态,客户端收到后,进入fin_wait_2
状态,等待服务端主动关闭连接,此时还能接受数据 - 第三次挥手:服务端此后没有数据发给客户端时,服务端会向客户端发送一个
FIN
,关闭服务端到客户端的连接 - 第四次挥手:客户端在收到之后会回复一个
ACK
,服务端收到后,关闭连接,立刻进入closed
状态,客户端在等待两个最大段生命周期(MSL)
之后,也关闭连接,进入closed
状态.
挥手成功,关闭连接成功。
你会不会有这样的疑问,为啥挥手是四次?
这是因为第一次发送FIN
时,客户端表明自己没有数据发送,但是还能接收数据;当服务端第二次发送ACK
,表明它已经知道客户端没有数据发送了,但是客户端还能接收数据;第三次服务端发送FIN
,表明自己也没有数据发送了,等到客户端第四次发ACK
过来, 服务端才关闭。
所以需要四次。
发送HTTP请求
建立好TCP连接后,然后就可以通过发送HTTP请求到服务器请求数据了。
一个HTTP请求由请求行
,请求报头
,空行
, 请求数据
组成
请求行
格式:Method Request-URL HTTP-Version CRLF
例子:GET /test.html HTTP/1.1
截至目前,请求方法有九种:
GET
, POST
, OPTION
, HEAD
, PUT
, DELETE
, CONNECT
, TRACE
, PATCH
常用的请求方法是GET
和 POST
请求报头(request header)
向服务器传输附加信息。常见的请求报头有:Accept
, Accept-Charset
, Accept-Encoding
, Accept-Language
, Content-Type
, Authorization
, Cookie
, User-Agent
等
Connection设置为Keep-alive, 用于告诉客户端本次HTTP请求结束之后并不需要关闭TCP连接,这样可以使下次HTTP请求使用相同的TCP通道,节省TCP连接建立的时间
空行
在请求报头和请求数据之间有个空行,表示上面是请求包头
,接下来的是请求数据
,用以区分二者。
请求数据
客户端向服务器传输的数据.
服务端返回的状态码
状态码 | 描述 |
---|---|
200 | 请求成功 |
204 | 请求成功,但是没有内容返回 |
301 | 请求的资源已被永久的移动到新的地方 |
302 | 请求的资源临时被移动到新的地方 |
304 | 所请求的资源未修改 |
400 | 请求语法有问题,服务端无法理解 |
403 | 服务器收到求,但是拒绝执行此请求 |
404 | 未找到资源 |
405 | 请求方法和服务器定义的方法不一样 |
500 | 服务器内部错误 |
浏览器解析
服务端把数据返回给浏览器,浏览器该如何解析呢?
如图所示:
- HTML通过HTML解析器解析输出DOM树
- css样式通过CSS解析器解析输出CSS规则
- 结合DOM树和CSS规则,计算出 DOM 树中每个节点的具体样式,生成渲染树
- 浏览器根据渲染树开始布局和绘制,会触发回流(reflow)和重绘(repaint)
- 构建图层树,显示页面
补充一点:
回流(reflow):当DOM的变化影响了元素的几何信息(元素的的位置和尺寸大小)的过程
发生的条件:
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
重绘(repaint):当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程
发生的条件:
- 改变元素的颜色、背景等属性
- visibility与opacity的使用
要尽量避免回流和重绘, 因为非常消耗性能
回流一定会发生重绘,重绘不一定会发生回流
总结
以上就是自己总结的页面从输入URL到渲染都发生了什么
,这个问题引出的知识点是非常多的,我只是大概的讲了整个流程,希望对你们理解这个问题有所帮助~