从输入URL到页面加载全过程
从简单讲:
1. DNS域名解析; 2. 建立TCP连接; 3. 发送HTTP请求; 4. 返回响应结果; 5. 关闭TCP连接; 6. 浏览器解析HTML; 7. 浏览器布局渲染; |
大家基本上都知道这些,但是里面的具体细节,大多数人还是不是很清楚,我们就细说一下:
为什么要做DNS域名解析?
网络通讯大部分是基于TCP/IP的,而TCP/IP是基于IP地址的,所以计算机在网络上进行通讯时只能识别如“202.96.134.133”之类的IP地址,而不能认识域名。我们无法记住10个以上IP地址的网站,所以我们访问网站时,更多的是在浏览器地址栏中输入域名,就能看到所需要的页面,这是因为有一个叫“DNS服务器”的计算机自动把我们的域名“翻译”成了相应的IP地址,然后调出IP地址所对应的网页。
*
互联网协议(Internet Protocol Suite)是一个网络通信模型,以及一整个网络传输协议家族,为互联网的基础通信架构。它常被通称为TCP/IP协议族(英语:TCP/IP Protocol Suite,或TCP/IP Protocols),简称TCP/IP。因为该协议家族的两个核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准。
一、DNS域名解析
我们在浏览器输入网址,其实就是要向服务器请求我们想要的页面内容,所有浏览器首先要确认的是域名所对应的服务器在哪里。将域名解析成对应的服务器IP地址这项工作,是由DNS服务器来完成的。
客户端收到你输入的域名地址后,它首先去找本地的hosts文件,检查在该文件中是否有相应的域名、IP对应关系,如果有,则向其IP地址发送请求,如果没有,再去找DNS服务器。一般用户很少去编辑修改hosts文件。
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服务器之间的交互属于迭代查询。 正常情况下,本地DNS服务器的缓存中已有comDNS服务器的地址,因此请求根域名服务器这一步不是必需的。
DNS缓存:
从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存(hosts文件),路由器缓存,IPS服务器(入侵防御系统(IPS: Intrusion Prevention System)是电脑网络安全设施)缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
二、Tcp 连接
费了一顿周折终于拿到服务器IP了,下一步自然就是链接到该服务器。对于客户端与服务器的TCP链接,必然要说的就是『三次握手』。
- 第一次握手:建立连接
客户端发送连接请求报文段,将SYN(同步序列编号(Synchronize Sequence Numbers))值设为1,Sequence Number为x。客户端进入SYN_SEND状态,等待服务器的确认。
- 第二次握手:服务器收到SYN报文段
服务器收到客户端SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number(确认号)为x+1(Sequence Number+1)。同时,自己还要发送SYN请求信息,将SYN值设为1,Sequence Number设为y。服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,服务器进入SYN_RECV状态。
- 第三次握手:客户端收到SYN+ACK报文段
客户端收到服务器的SYN+ACK报文段后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。
完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:
- 未连接队列:在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED(建立)状态。 Backlog参数:表示未连接队列的最大容纳数目。
- SYN-ACK 重传次数:服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从未连接队列中删除。注意,每次重传等待的时间不一定相同。
- 未连接存活时间:是指未连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称未连接存活时间为Timeout时间、SYN_RECV存活时间。
为什么是三次握手
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误
“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
三、发起Http请求
HTTP--Hyper Text Transfer Protocol,超文本传输协议,是一种建立在TCP上的无状态连接,整个基本的工作流程是客户端发送一个HTTP请求,说明客户端想要访问的资源和请求的动作,服务端收到请求之后,服务端开始处理请求,并根据请求做出相应的动作访问服务器资源,最后通过发送HTTP响应把结果返回给客户端。其中一个请求的开始到一个响应的结束称为事务,当一个事物结束后还会在服务端添加一条日志条目。
Http会发起一次请求request报文,它包括:请求行(request line)、请求头部(header)、空行和请求数据这四个部分。
1.请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。
POST /clues/get_clues_detail HTTP/1.1
HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT。
而常见的有如下几种:
GET: 完整请求一个资源 (常用) HEAD: 仅请求响应首部 POST:提交表单 (常用) PUT: (webdav) 上传文件(但是浏览器不支持该方法) DELETE:(webdav) 删除 OPTIONS:返回请求的资源所支持的方法 TRACE: 追求一个资源请求中间所经过的代理(该方法不能由浏览器发出) |
2.请求头
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:、
Accept: 客户端可识别的内容类型列表。 Accept-Encoding: 声明浏览器支持的编码类型。 Cache-Control: 指定了请求和响应遵循的缓存机制。 Connection: 决定当前的事务完成后,是否会关闭网络连接。如果该值是“keep-alive”,网络连接就是持久的,不会关闭,使得对同一个服务器的请求可以继续在该连接上完成。 Host: 请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。 Referer: 告诉服务器从哪个页面链接过来的,服务器藉此可以获得一些信息用于处理。 Upgrade-Insecure-Requests: 让浏览器自动升级请求从http到https,用于大量包含http资源的http网页直接升级到https而不会报错。 User-Agent: 产生请求的浏览器类型。 |
3.空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
4.请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
四、返回响应结果
HTTP响应也由三个部分组成,分别是:状态行、相应头部、响应正文。
HTTP/1.1 200 OK
1.状态行
HTTP-Version Status-Code Reason-Phrase CRLF
其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。
1xx:指示信息–表示请求已接收,继续处理。
2xx:成功–表示请求已被成功接收、理解、接受。
3xx:重定向–要完成请求必须进行更进一步的操作。
4xx:客户端错误–请求有语法错误或请求无法实现。
5xx:服务器端错误–服务器未能实现合法的请求。
常见状态代码、状态描述的说明如下。
200 OK:客户端请求成功。
301: 永久重定向, Location响应首部的值仍为当前URL,因此为隐藏重定向。
302: 临时重定向,显式重定向, Location响应首部的值为新的URL。
304:Not Modified 未修改,比如本地缓存的资源文件和服务器上比较时,发现并没有修改,服务器返回一个304状态码,告诉浏览器,你不用请求该资源,直接使用本地的资源即可。
400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务。
404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
500 Internal Server Error:服务器发生不可预期的错误。
502: Bad Gateway 前面代理服务器联系不到后端的服务器时出现
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。
504:Gateway Timeout 这个是代理能联系到后端的服务器,但是后端的服务器在规定的时间内没有给代理服务器响应
2.响应头部
如下是Chrome浏览器的响应头部:
Connection 使用keep-alive特性
Content-Length WEB服务器告诉浏览器自己响应的对象的长度或尺寸,例如:Content-Length: 2284
Content-Encoding 使用gzip方式对资源压缩
Content-type MIME类型为html类型,字符集是 UTF-8
Date 响应的日期
Server 使用的WEB服务器
Transfer-Encoding:chunked 分块传输编码 是http中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用(通常是网页浏览器)的数据可以分成多个部分,分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供
HTTP响应头和请求头信息对照表:http://tools.jb51.net/table/http_header
维持链接
完成一次 HTTP 请求后,服务器并不是马上断开与客户端的连接。在 HTTP/1.1 中,Connection: keep-alive 是默认启用的,表示持久连接,以便处理不久后到来的新请求,无需重新建立连接而增加慢启动开销,提高网络的吞吐能力。在反向代理软件 Nginx 中,持久连接超时时间默认值为 75 秒,如果 75 秒内没有新到达的请求,则断开与客户端的连接。同时,浏览器每隔 45 秒会向服务器发送 TCP keep-alive 探测包,来判断 TCP 连接状况,如果没有收到 ACK 应答,则主动断开与服务器的连接。注意,HTTP keep-alive 和 TCP keep-alive 虽然都是一种保活机制,但是它们完全不相同,一个作用于应用层,一个作用于传输层。
五、关闭TCP连接
- 第一次挥手:客户端想分手
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包(FIN=1,seq=x),表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。
- 第二次挥手:服务端也想分手
服务器端确认客户端的 FIN包,发送一个确认包(ACK=1,ACKnum=x+1),表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入FIN_WAIT_2 状态,等待服务器端关闭连接。
- 第三次挥手:服务端准备好分手
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN置为1(FIN=1,seq=y)。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
- 第四次挥手:分手
客户端接收到来自服务器端的关闭请求,发送一个确认包(ACK=1,ACKnum=y+1),并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。
客户端等待2MSL(2MSL,2 Maximum Segment Lifetime)之后,没有收到回复,确保服务器端确实是关闭了,客户端也关闭连接,进入 CLOSED状态。
六、浏览器解析HTML
浏览器通过http协议收到服务器发来的http response之后,需要对收到的http response中实体部分的HTML文本进行处理,也即解析,具体过程如下:
文档对象模型 (DOM)
解析页面标签生成DOM树
生成DOM树的过程:
字节 → 字符 → 标签 → 节点 → DOM树
Bytes → characters → tokens → nodes → object model
生成DOM树的规则
DOM树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
CSS 对象模型 (CSSOM)
在浏览器构建这个简单页面的 DOM 过程中,在文档的 head 中遇到了一个 link 标记,该标记引用一个外部 CSS 样式表:style.css。由于预见到需要利用该资源来渲染页面,它会立即发出对该资源的请求,并返回以下内容:
body { font-size: 16px } p { font-weight: bold } span { color: red } p span { display: none } img { float: right }
我们本可以直接在 HTML 标记内声明样式(内联),但让 CSS 独立于 HTML 有利于我们将内容和设计作为独立关注点进行处理:设计人员负责处理 CSS,开发者侧重于 HTML,等等。
与处理 HTML 时一样,我们需要将收到的 CSS 规则转换成某种浏览器能够理解和处理的东西。因此,我们会重复 HTML 过程,不过是为 CSS 而不是 HTML。
CSS 字节转换成字符,接着转换成tokens和节点,最后链接到一个称为“CSS 对象模型”(CSSOM) 的树结构。
浏览器会解析 HTML 成树形的数据结构DOM,生成 DOM Tree,浏览器将CSS代码解析成树形的数据结构CSSOM,生成 CSS Rule Tree。
DOM Tree和CSS Rule Tree结合生成Render Tree。
display:none 的节点不会被加入Render Tree,而visibility: hidden 则会。
• display : 隐藏对应的元素但不挤占该元素原来的空间。
• visibility: 隐藏对应的元素并且挤占该元素原来的空间
所以,如果某个节点最开始是不显示的,设为display:none是更优的。
七、浏览器布局渲染
解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树
这里先解释一下几个概念,方便大家理解:
- DOM Tree:浏览器将HTML解析成树形的数据结构。
- CSS Rule Tree:浏览器将CSS解析成树形的数据结构。
- Render Tree: DOM和CSSOM合并后生成Render Tree。
- layout(布局): 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。
- painting(绘制): 按照算出来的规则,通过显卡,把内容画到屏幕上。
- reflow(回流):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,内行称这个回退的过程叫 reflow。reflow 会从 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
- repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。
注意:
- display:none 的节点不会被加入Render Tree,而visibility: hidden 则会,所以,如果某个节点最开始是不显示的,设为display:none是更优的。
- display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发现位置变化。
- 有些情况下,比如修改了元素的样式,浏览器并不会立刻reflow 或 repaint 一次,而是会把这样的操作积攒一批,然后做一次 reflow,这又叫异步 reflow 或增量异步 reflow。但是在有些情况下,比如resize 窗口,改变了页面默认的字体等。对于这些操作,浏览器会马上进行 reflow。
注意: 上述这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。 |
性能优化中重绘、重排:
(1)Reflow(回流/重排):当它发现了某个部分发生了变化影响了布局,渲染树需要重新计算。
(2)Repaint(重绘):改变了某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的repaint,根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随重排;
Reflow要比Repaint更花费时间,也就更影响性能。所以在写代码的时候,要尽量避免过多的Reflow。
reflow的原因:
(1)页面初始化的时候;
(2)操作DOM时;
(3)某些元素的尺寸变了;
(4)如果 CSS 的属性发生变化了。
减少 reflow/repaint
(1)不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className。
(2)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。
(3)为动画的 HTML 元件使用position: fixed 或 absoult 的,那么修改他们的 CSS 是不会 reflow 的。
(4)尽量不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。
其他
一。根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
1.GET
请求指定的页面信息,并返回实体主体。
2.HEAD
类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3.POST
向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4.PUT
从客户端向服务器传送的数据取代指定的文档的内容。
5.DELETE
请求服务器删除指定的页面。
6.CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7.OPTIONS
允许客户端查看服务器的性能。
8.TRACE
回显服务器收到的请求,主要用于测试或诊断。
二。dsn缓存失效问题:
https://blog.csdn.net/lock_xuanqing/article/details/80334579
三。DNS递归查询与迭代查询:
1.递归查询:
一般客户机和服务器之间属递归查询,即当客户机向DNS服务器发出请求后,若DNS服务器本身不能解析,则会向另外的DNS服务器发出查询请求,得到结果后转交给客户机;
2.迭代查询(反复查询):
一般DNS服务器之间属迭代查询,如:若DNS2不能响应DNS1的请求,则它会将DNS3的IP给DNS2,以便其再向DNS3发出请求;
举例:比如学生问老师一个问题,王老师告诉他答案这之间的叫递归查询。这期间也许王老师也不会,这时王老师问张老师,这之间的查询叫迭代查询!
递归是用户只向本地DNS服务器发出请求,然后等待肯定或否定答案。而迭代是本地服务器向根DNS服务器发出请求,而根DNS服务器只是给出下一级DNS服务器的地址,然后本地DNS服务器再向下一级DNS发送查询请求直至得到最终答案。
后来发现了图文结合总结的更简洁易懂的文章:
https://www.xuecaijie.com/it/157.html#1Q64p5DeC8dKFF
http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/
关于浏览器渲染的文章推荐:
https://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/
https://www.jianshu.com/p/125c5e9159b5