当你开始输入网址好比www.cnblogs.com时游览器就能够在书签或者历史记录里面去搜索相关的网址推荐给你。javascript
导航的第一步是经过访问的域名找出其IP地址。DNS查找过程以下:css
浏览器缓存 – 浏览器会缓存DNS记录一段时间。 有趣的是,操做系统没有告诉浏览器储存DNS记录的时间,这样不一样浏览器会储存个自固定的一个时间(2分钟到30分钟不等)。html
系统缓存 – 若是在浏览器缓存里没有找到须要的记录,浏览器会作一个系统调用(windows里是gethostbyname)。这样即可得到系统缓存中的记录。java
路由器缓存 – 接着,前面的查询请求发向路由器,它通常会有本身的DNS缓存。node
ISP DNS 缓存 – 接下来要check的就是ISP缓存DNS的服务器。在这通常都能找到相应的缓存记录。web
递归搜索 – 你的ISP的DNS服务器从跟域名服务器开始进行递归搜索,从.com顶级域名服务器到Facebook的域名服务器。通常DNS服务器的缓存中会有.com域名服务器中的域名,因此到顶级服务器的匹配过程不是那么必要了。面试
① 请求发起后,游览器首先会解析这个域名,首先它会查看本地硬盘的 hosts 文件,看看其中有没有和这个域名对应的规则,若是有的话就直接使用 hosts 文件里面的 ip 地址。数据库
② 若是在本地的 hosts 文件没有可以找到对应的 ip 地址,浏览器会发出一个 DNS请求到本地DNS(域名分布系统)服务器 。本地DNS服务器通常都是你的网络接入服务器商提供,好比中国电信,中国移动。windows
③查询你输入的网址的DNS请求到达本地DNS服务器以后,本地DNS服务器会首先查询它的缓存记录,若是缓存中有此条记录,就能够直接返回结果,此过程是递归的方式进行查询。若是没有,本地DNS服务器还要向DNS根服务器进行查询浏览器
④根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你能够到域服务器上去继续查询,并给出域服务器的地址。这种过程是迭代的过程
⑤本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求以后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址
⑥最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不只要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,能够直接返回结果,加快网络访问。
相关问题:
什么是DNS劫持?
DNS劫持(Domain Name System,域名劫持),是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围之外的请求放行,返回假的IP地址或者什么都不作使请求失去响应,其效果就是对特定的网络不能访问或访问的是假网址。简单来讲,就是你输入的是知乎的网址,可是却跳转到了百度的页面。
TCP/IP 分为四层,在发送数据时,每层都要对数据进行封装:
在前面的步骤咱们已经获得服务器的 IP 地址,浏览器会开始构造一个 HTTP 报文,其中包括:
其中须要注意的点:
传输层会发起一条到达服务器的 TCP 链接,为了方便传输,会对数据进行分割(以报文段为单位),并标记编号,方便服务器接受时可以准确地还原报文信息。
在创建链接前,会先进行 TCP 三次握手。
关于 TCP/IP 三次握手,网上已经有不少段子和图片生动地描述了。
相关知识点:
将数据段打包,并加入源及目标的IP地址,而且负责寻找传输路线。
判断目标地址是否与当前地址处于同一网络中,是的话直接根据 Mac 地址发送,不然使用路由表查找下一跳地址,以及使用 ARP 协议查询它的 Mac 地址。
注意:在 OSI 参考模型中 ARP 协议位于链路层,但在 TCP/IP 中,它位于网络层。
以太网协议
根据以太网协议将数据分为以“帧”为单位的数据包,每一帧分为两个部分:
Mac 地址
以太网规定了连入网络的全部设备都必须具有“网卡”接口,数据包都是从一块网卡传递到另外一块网卡,网卡的地址就是 Mac 地址。每个 Mac 地址都是独一无二的,具有了一对一的能力。
广播
发送数据的方法很原始,直接把数据经过 ARP 协议,向本网络的全部机器发送,接收方根据标头信息与自身 Mac 地址比较,一致就接受,不然丢弃。
注意:接收方回应是单播。
相关知识点:
接受过程就是把以上步骤逆转过来,参见上图。
大体流程
HTTPD
最多见的 HTTPD 有 Linux 上经常使用的 Apache 和 Nginx,以及 Windows 上的 IIS。
它会监听获得的请求,而后开启一个子进程去处理这个请求。
处理请求
接受 TCP 报文后,会对链接进行处理,对HTTP协议进行解析(请求方法、域名、路径等),而且进行一些验证:
重定向
假如服务器配置了 HTTP 重定向,就会返回一个 301
永久重定向响应,浏览器就会根据响应,从新发送 HTTP 请求(从新执行上面的过程)。
URL 重写
而后会查看 URL 重写规则,若是请求的文件是真实存在的,好比图片、html、css、js文件等,则会直接把这个文件返回。
不然服务器会按照规则把请求重写到 一个 REST 风格的 URL 上。
而后根据动态语言的脚本,来决定调用什么类型的动态文件解释器来处理这个请求。
以 PHP 语言的 MVC 框架举例,它首先会初始化一些环境的参数,根据 URL 由上到下地去匹配路由,而后让路由所定义的方法去处理请求。
浏览器接收到来自服务器的响应资源后,会对资源进行分析。
首先查看 Response header,根据不一样状态码作不一样的事(好比上面提到的重定向)。
若是响应资源进行了压缩(好比 gzip),还须要进行解压。
而后,对响应资源作缓存。
接下来,根据响应资源里的 MIME 类型去解析响应内容(好比 HTML、Image各有不一样的解析方式)。
三、创建TCP连接
在拿到域名对应的IP地址后,会以随机端口(1024~~65535)向WEB服务器程序80端口发起TCP的链接请求,这个链接请求进入到内核的TCP/IP协议栈(用于识别该链接请求,解封包,一层一层的剥开),还有可能要通过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序,最终创建了TCP/IP的链接,对于客户端与服务器的TCP连接,必然要说的就是『三次握手』。
客户端发送一个带有SYN标志的数据包给服务端,服务端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息,最后客户端再回传一个带ACK标志的数据包,表明握手结束,链接成功。
通俗化以后就是:
客户端:老弟我要跟你连接
服务端:好的,赞成了
客户端:好嘞
创建TCP链接以后,发起HTTP请求,请求通常分为三部分
请求方法URI协议/版本
请求头(Request Header)
请求正文
下面是一个完整的请求
五、服务器端处理
服务器端收到请求后的由web服务器(准确说应该是http服务器)处理请求,诸如Apache、Ngnix、IIS等。web服务器解析用户请求,知道了须要调度哪些资源文件,再经过相应的这些资源文件处理用户请求和参数,并调用数据库信息,最后将结果经过web服务器返回给浏览器客户端。
为了不服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方均可以发起关闭请求。与建立TCP链接的3次握手相似,关闭TCP链接,须要4次握手。
能够通俗化:
客户端:老弟,我这边没数据要传了,我们关闭连接吧
服务端:好的,接收到了,我看看我这边还有没有要传的
服务端:我这边也没有了,关闭吧
客户端:好嘞
三次握手&四次挥手以后
当网络进程接收到的响应报文状态码,进行相应的操做。例如状态码为 200 OK
时,会解析响应报文中的 Content-Type
首部字段,例如咱们这个过程 Content-Type
会出现 application/javascript
、text/css
、text/html
,即对应 Javascript
文件、CSS
文件、HTML
文件。
对于获取到的HTML、CSS、JS、图片等等资源。
浏览器经过解析HTML,生成DOM树,解析CSS,生成CSS规则树,而后经过DOM树和CSS规则树生成渲染树。渲染树与DOM树不一样,渲染树中并无head、display为none等没必要显示的节点。
在解析CSS的同时,能够继续加载解析HTML,但在解析执行JS脚本时,会中止解析后续HTML,这就会出现阻塞问题,关于JS阻塞相关问题,这里不过多阐述,后面会单独开篇讲解。
你们都知道页面渲染的过程也是面试中单独会考的点,而且时常会由这个点延申出另外一个问题,即如何避免回流和重绘。
渲染过程,是整个从理器输入 URL 到页面渲染过程的最后一步。而页面渲染的过程能够分为 9 个步骤:
HTML
生成 DOM
树CSS
生成 CSSOM
JavaScript
Render Tree
)2.5.1 构建 DOM 树
因为网络进程传输给渲染进程的是 HTML
字符串,因此,渲染进程须要将 HTML
字符串转化成 DOM
树。
须要注意的是这个 DOM
树不一样于 Chrome-devtool
中 Element
选项卡的 DOM
树,它是存在内存中的,用于提供 JavaScript
对 DOM
的操做。
构建 CSSOM
构建 CSSOM
的过程,即经过解析 CSS
文件、style
标签、行内 style
等,生成 CSSOM
。而这个过程会作这几件事:
规范 CSS
,即将 color: blue
转化成 color: rgb()
形式,能够理解成相似 ES6
转 ES5
的过程
计算元素样式,例如 CSS
样式会继承父级的样式,如 font-size
、color
之类的。
CSS Object Model
是一组容许用 JavaScript
操纵 CSS
的 API
。详细 API
讲解能够看 MDN
加载 JavaScript
一般状况下,在构建 DOM
树或 CSSOM
的同时,若是也要加载 JavaScript
,则会形成前者的构建的暂停。固然,咱们能够经过 defer
或 sync
来实现异步加载 JavaScript
。虽然 defer
和 sync
均可以实现异步加载 JavaScript
,可是前者是在加载后,等待 CSSOM
和 DOM
树构建完后才执行 JavaScript
,然后者是在异步加载完立刻执行,即便用 sync
的方式仍然会形成阻塞。
而 JavaScript
执行的过程,即编译和运行 JavaScript
的过程。因为 JavaScript
是解释型的语言。因此这个过程会是这样的:
Token
化Token
,生成 AST
(Abstract Sytanx Tree
) 抽象语法树和建立上下文AST
,生成字节码。在有了 DOM
树和 CSSOM
以后,须要将二者结合生成渲染树 Render Tree
,而且这个过程会去除掉那些 display: node
的节点。此时,渲染树就具有元素和元素的样式信息。
根据 Render Tree
渲染树,对树中每一个节点进行计算,肯定每一个节点在页面中的宽度、高度和位置。
须要注意的是,第一次肯定节点的大小和位置的过程称为布局,而第二次才被称为回流
因为层叠上下文的存在,渲染引擎会为具有层叠上下文的元素建立对应的图层,而诸多图层的叠加就造成了咱们看到的一些页面效果。例如,一些 3D
的效果、动画就是基于图层而造成的。
值得一提的是,对于内容溢出存在滚轮的状况也会进行分层
对于存在图层的页面部分,须要进行有序的绘制,而对于这个过程,渲染引擎会将一个个图层的绘制拆分红绘制指令,并按照图层绘制顺序造成一个绘制列表。
光栅化
有了绘制列表后,渲染引擎中的合成线程会根据当前视口的大小将图层进行分块处理,而后合成线程会对视口附近的图块生成位图,即光栅化。而渲染进程也维护了一个栅格化的线程池,专门用于将图块转为位图。
栅格化的过程一般会使用 GPU
加速,例如使用 wil-change
、opacity
,就会经过 GPU
加速
显示
当全部的图块都通过栅格化处理后,渲染引擎中的合成线程会生成绘制图块的指令,提交给浏览器进程。而后浏览器进程将页面绘制到内存中。最后将内存绘制结果显示在用户界面上。
而这个整个从生成绘制列表、光栅化、显示的过程,就是咱们常说的重绘的过程
结语
整个浏览器输入 URL 到页面渲染的过程涉及到的知识点很是广,如 Chrome
多进程的架构、HTTP
通讯过程、浏览器解析 JavaScript
过程、浏览器绘制页面过程以及一些计算机的基础知识等等,而且,这整个过程的分析其实和 Chrome-devtools
密切相关。