- 浏览器的地址栏输入URL并按下回车。
- 浏览器查找当前URL的DNS缓存记录。
- 没有缓存记录,DNS解析URL对应的IP。
- 查看浏览器缓存
- 没有数据缓存,根据IP建立TCP连接,发送HTTP请求并响应。
- 浏览器处理数据。
一、在浏览器的地址中敲入URL
URL是什么
URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上的资源,实际上就是网站网址。url的格式一般为:
协议、网络地址、资源路径、文件名、动态参数
URL完整格式为:协议://子域名.域名.顶级域名:端口号/目录/文件名.文件后缀?参数=值#标志
协议/模式(scheme):是从该计算机获取资源的方式,一般有Http、Https、Ftp、File、Mailto、Telnet、News等协议,不同协议有不同的通讯内容格式,协议主要作用是告诉浏览器如何处理将要打开的文件;
网络地址:指示该连接网络上哪一台计算机(服务器),可以是域名或者IP地址,域名或IP地址后面有时还跟一个冒号和一个端口号;
端口号:如果地址不包含端口号,根据协议的类型会确定一个默认端口号。端口号之于计算机就像窗口号之于银行,一家银行有多个窗口,每个窗口都有个号码,不同窗口可以负责不同的服务。端口只是一个逻辑概念,和计算机硬件没有关系。一般如果你的端口号就是默认的,那么url是不需要输入端口号的,但如果你更改了默认端口号,你就必须要在url后输入新端口号才能正常访问。例如:http协议默认端口号是80。如果你输入的url是http://www.zhihu.com:8080/ ,那表示不使用默认的端口号,而使用指定的端口号8080。如果使用的就是默认端口号那么输入http://www.zhihu.com:80 和http://www.zhihu.com是一样的。有个特殊情况有所不同,比如本地IP 127.0.0.1 其实走的是 loopback,和网卡设备没关系。
资源路径:指示从服务器上获取某一项资源的等级结构路径,以斜线/
分隔;
文件名:一般是需要真正访问的文件,有时候,URL以斜杠“/”结尾,而隐藏了文件名,在这种情况下,URL引用路径中最后一个目录中的默认文件(通常对应于主页),这个文件常被称为 index.html 或 default.htm。
动态参数:有时候路径后面会有以问号?
开始的参数,这一般都是用来传送对服务器上的数据库进行动态询问时所需要的参数,有时候没有,很多为了seo优化,都已处理成伪静态了。要注意区分url和路由的区别
例如我的某篇博客url:长短连接,长短轮询
- 协议类型:https
- 网络地址:(子/三级域名 . 二级域名. 顶/一级域名)
- 端口号:443,因为默认,所以不显示
IP是什么
IP是因特网中的每台连接到网络的计算机为实现相互通信而遵循的规则协议。每个处于互联网中的设备都有IP 地址,形如 192.168.0.1,而127.0.0.1代表本机的 IP。
用户与因特网上的某个主机通信时,必须知道对方的IP地址。然而用户很难记住长达32位二级制主机地址(IPv4,IPv6地址:126位),所以应用层为了便于用户记忆各种网络应用,更多使用主机名
所以,为了便于记忆或辨识,人们使用域名来登录网站,每个域名背后有对应的IP地址。
比如对于 的URL,浏览器实际上不知道 到底是什么东西,需要查找 网站所在服务器的IP地址,才能找到目标,这就是下文要说的域名解析。
二、域名解析
1、什么是DNS
域名系统DNS(Domain Name System)是因特网使用的命名系统,用来把便于人们使用的机器名字转换为IP地址。IP地址对应着网络上一台计算机。
因特网的域名系统DNS被设计成一个联机分布式数据库系统,并采用客户-服务器方式。DNS大多数名字都在本地进行解析,仅少量解析需要在因特网上通信,因此DNS系统的效率很高。由于DNS是分布式系统,即使单个计算机出了故障,也不会妨碍整个DNS系统的正常运行。
域名到IP地址的解析是由分布在因特网上的许多与域名服务器程序(可简称为域名服务器)共同完成的。域名服务器程序在专设的节点上运行,人们也常把运行域名服务器程序的机器称为域名服务器
域名解析的过程实际是将域名还原为IP地址的过程。
请求一旦发起,浏览器首先要做的事情就是解析这个域名
DNS查询顺序:浏览器缓存→系统缓存→路由器缓存→ISP DNS 缓存→迭代 / 递归搜索
2、从缓存中解析
- 浏览器缓存
有dns的地方,就有缓存。一般来说,浏览器会检查缓存中有没有这个域名对应的解析过的IP地址,如果缓存中有,这个解析过程就将结束。(chorme:chrome://net-internals/#dns)
- 操作系统缓存
如果用户的浏览器缓存中没有,浏览器会从本地硬盘的hosts文件查找是否有存储DNS信息,查找是否有目标域名和对应的IP地址,如果有的话就直接使用 hosts 文件里面的 ip 地址。
- 路由器缓存
如果系统缓存中也找不到,那么查询请求就会发向路由器,路由器一般会有自己的DNS缓存。
- ISP(Internet Service Provider,Internet服务供应商,用户接入Internet的接口) DNS 缓存
如果路由器缓存中也找不到,那么就查询ISP DNS 缓存服务器,即电脑会发出一个DNS请求到本地DNS服务器。
我们都知道在我们的网络配置中都会有"DNS服务器地址"这一项,操作系统会把这个域名发送给这里设置的DNS,比如114.114.114.114
,也就是本地区的域名服务器,通常是给你接入互联网的应用提供商提供。而114.114.114.114
是国内移动、电信和联通通用的DNS。
3、从因特网上解析,DNS查询的两种方式:递归查询和迭代查询
- 当本地DNS服务器不能回答客户机的DNS查询时,它就需要向其他DNS服务器进行查询并进行解析。此时有两种方式。
递归解析。
本地域名服务器以DNS客户的身份,一般是先向该域名的根域服务器发出查询请求报文,再由根域名服务器一级级向下查询。最后得到的查询结果返回给本地DNS服务器,再由本地DNS服务器返回给客户端。
因此递归查询返回的查询结果或者是所要查询的IP地址,或者是报错,表示无法查询到所需的IP地址。
迭代解析。
当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地服务器:“你下一步应当向哪一个域名服务器进行查询(给出IP地址)。”然后让本地域名服务器再继续向这些DNS服务器进行查询(而不是替本地域名服务器进行后续的查询),到得到查询结果为止。
也就是说,迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。比如说:baidu.com的服务器ip地址在192.168.4.5这里,你自己去查吧,本人比较忙,只能帮你到这里了。
采用哪种递归方式,取决于最初的查询请求报文的设置是要求哪一种查询方式
3、迭代 / 递归两种解析的步骤
假设域名为 m.xyz.com 的主机想要知道另一个主机(域名为s.microsoft.com)的IP地址。例如主机 m.xyz.com 打算发送邮件给主机 s.microsoft.com、这时就需要知道主机 s.microsoft.com的IP地址。
递归:按根域服务器 ---> 本地域名服务器 ---> 顶级域.con ---> 二级域.miscrosoft.com ---> 权限域名服务example.microsoft.com 查询得到主机的IP地址---> 按上一级DNS服务器->上上级->....逐级向上返回IP给主机用户
迭代:按根域服务器 ---> 本地域名服务器 ---> 顶级域.cn ---> 本地域名服务器 ---> 第二层域 miscrosoft.com ---> 本地域名服务器 ---> 权限域 example.microsoft.com (得到IP地址)---> 本地域名服务器 的顺序找到IP地址。
迭代查询:这10个步骤总共使用10个UDP用户数据报的报文。本地域名服务器经过四次迭代查询后,从权限域名服务器example.microsoft.com得到了主机 S.microsoft.com 的IP地址,最后把结果返回给了发起查询的主机
递归查询:本地域名服务器只需向根域名服务器查询一次,后面几次查询都是在其他几个域名服务器之间进行。只是在步骤A4,本地域名服务器从根域名服务器得到了所需的IP地址,最后再在5,本地域名服务器吧查询结果告诉了主机。整个查询使用了10个UDP报文
4、DNS递归查询和迭代查询的区别?
递归查询:没有以谁为中心,是服务器和服务器之间的查询活动,递归查询的过程中“查询的递交者” 一直在更替,其结果是直接告诉本地域名服务器需要查询的网站目标IP地址,再有本地域名服务器告诉客户端。
迭代查询:本地名称服务器为中心的,是本地名称服务器和服务器之间的查询活动,迭代查询的过程中“查询的递交者”一直没变化,其结果是间接告诉本地名称服务器另一个DNS服务器的地址,最后权限域服务器告诉本地域名服务器目标网站IP地址。
5、DNS域名称空间的组织方式
我们在前面有说到根DNS服务器,域DNS服务器,这些都是DNS域名称空间的组织方式。按其功能命名空间中用来描述 DNS 域名称的五个类别的介绍详见下表中,以及与每个名称类型的示例
三、查看浏览器缓存
根据是否需要重新向服务器发起请求来分类,浏览器缓存分为:
- 强缓存(如果资源存在,且maxAge未过时直接读取本地磁盘缓存,无需建立连接)
- 协商缓存(服务端根据 Last-modified + etag 判断数据是否更新,若更新则返回200 +新数据,否则返回403, 读取本地资源)
首先判断是否命中强缓存,如果不命中强缓存或资源过期,则走协商缓存,即建立TCP连接,进行HTTP请求。
简单回顾 强缓存、协商缓存需要的头文件数据
强制缓存判断HTTP首部字段:cache-control,Expires。
Expires是一个绝对时间,即服务器时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。但是该方法存在一个问题:服务器时间与客户端时间可能不一致。因此该字段已经很少使用。
cache-control中的max-age保存一个相对时间。例如Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在484200s内均有效。 如果同时存在cache-control和 Expires,浏览器总是优先使用cache-control。
协商缓存通过HTTP的last-modified,Etag字段进行判断。
last-modified是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送if-modified-since字段。服务器用本地Last-modified时间与if-modified-since时间比较,如果不一致则认为缓存已过期并返回新资源给浏览器;如果时间一致则发送304状态码,让浏览器继续使用缓存。
Etag:资源的实体标识(哈希字符串),当资源内容更新时,Etag会改变。服务器会判断Etag是否发生变化,如果变化则返回新资源,否则返回304。
四、 应用层客户端发送HTTP请求
互联网内各网络设备间的通信都遵循TCP/IP协议,利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。分层由高到低分别为:应用层、传输层、网络层、数据链路层。发送端从应用层往下走,接收端从数据链路层网上走。如图所示:
从上面的步骤中得到 IP 地址后,浏览器会开始构造一个 HTTP 请求,应用层客户端向服务器端发送的HTTP请求包括:请求报头和请求主体两个部分,其中请求报头(request header)包含了至关重要的信息,包括
- 请求的方法(GET / POST和不常用的PUT / DELETE以及更不常用的HEAD / OPTION / TRACE,一般的浏览器只能发起 GET 或者 POST 请求)、
- 目标url、
- 遵循的协议(HTTP / HTTPS / FTP…),
- 返回的信息是否需要缓存,
- 以及客户端是否发送Cookie等信息。
需要注意的是,因为 HTTP 请求是纯文本格式的,所以在 TCP 的数据段中可以直接分析 HTTP 文本的。
五、传输层TCP传输报文
当应用层的 HTTP 请求准备好后,浏览器会在传输层发起一条到达服务器的 TCP 连接,位于传输层的TCP协议为传输报文提供可靠的字节流服务。它为了方便传输,将大块的数据分割成以报文段为单位的数据包进行管理,并为它们编号,方便服务器接收时能准确地还原报文信息。TCP协议通过“三次握手”等方法保证传输的安全可靠。“三次握手”的过程是,
第一次握手: 客户端发送带有SYN(syn=j)标志的数据包给接收端,并进入SYN_SENT状态,等待服务器确认;
第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即带有SYN、ACK表示的数据包,此时服务器进入SYN_RECV状态;(表示可以收到客户端的请求)
第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。(表示可以收到服务器端的数据)
传输层以下的细节:
1. 网络层IP协议查询MAC地址
IP协议的作用是把TCP分割好的各种数据包封装到IP包里面传送给接收方。而要保证确实能传到接收方还需要接收方的MAC地址,也就是物理地址才可以。IP地址和MAC地址是一一对应的关系,一个网络设备的IP地址可以更换,但是MAC地址一般是固定不变的。ARP协议可以将IP地址解析成对应的MAC地址。当通信的双方不在同一个局域网时,需要多次中转才能到达最终的目标,在中转的过程中需要通过下一个中转站的MAC地址来搜索下一个中转目标。
2. 数据到达数据链路层
在找到对方的MAC地址后,已被封装好的IP包再被封装到数据链路层的数据帧结构中,将数据发送到数据链路层传输,再通过物理层的比特流送出去。这时,客户端发送请求的阶段结束。
这些分层的意义在于分工合作,数据链路层通过 CSMA/CD 协议保证了相邻两台主机之间的数据报文传递,而网络层的 IP 数据包通过不同子网之间的路由器的路由算法和路由转发,保证了互联网上两台遥远主机之间的点对点的通讯,不过这种传输是不可靠,于是可靠性就由传输层的 TCP 协议来保证,TCP 通过慢开始,乘法减小等手段来进行流量控制和拥塞避免,同时提供了两台遥远主机上进程到进程的通信,最终保证了 HTTP 的请求头能够被远方的服务器上正在监听的 HTTP 服务器进程收到,终于,数据包在跳与跳之间被拆了又封装,在子网与子网之间被转发了又转发,最后进入了服务器的操作系统的缓冲区,服务器的操作系统由此给正在被阻塞住的 accept 函数一个返回,将他唤醒。
3. 服务器接收数据
接收端的服务器在链路层接收到数据包,再层层向上直到应用层。这过程中包括在传输层通过TCP协议将分段的数据包重新组成原来的HTTP请求报文。
4. 服务器响应请求并返回相应文件
服务接收到客户端发送的HTTP请求后,服务器上的的 http 监听进程会得到这个请求,然后一般情况下会启动一个新的子进程去处理这个请求,同时父进程继续监听。http 服务器首先会查看重写规则,然后如果请求的文件是真实存在,例如一些图片,或 html、css、js 等静态文件,则会直接把这个文件返回,如果是一个动态的请求,那么会根据 url 重写模块的规则,把这个请求重写到一个 rest 风格的 url 上,然后根据动态语言的脚本,来决定调用什么类型的动态文件脚本解释器来处理这个请求。
六、浏览器开始处理数据信息并渲染页面
1、响应码判断
历经千辛万苦,我们请求的响应终于成功到达了客户端的浏览器,响应到达浏览器之后,浏览器首先会根据返回的响应报文里的一个重要信息——状态码,来做个判断。
如果是 200 开头的就好办,表示请求成功,直接进入渲染流程,
如果是 300 开头的就要去相应头里面找 location 域,根据这个 location 的指引,进行跳转,这里跳转需要开启一个跳转计数器,是为了避免两个或者多个页面之间形成的循环的跳转,当跳转次数过多之后,浏览器会报错,同时停止。比如:301表示永久重定向,即请求的资源已经永久转移到新的位置。在返回301状态码的同时,响应报文也会附带重定向的url,客户端接收到后将http请求的url做相应的改变再重新发送。
如果是 400 开头或者 500 开头的状态码,浏览器也会给出一个错误页面。比如:404 not found 就表示客户端请求的资源找不到。
2、页面显示
浏览器对后台返回的HTML字符串进行读取解析。
从得到数据到页面显示,浏览器经过:加载、解析、渲染。
- 加载
浏览器对一个html页面的加载顺序是从上而下的。如果加载过程中
- 如果遇到了 style 标签包围起来的 css 代码,也会保存下来,用于稍后的渲染。
- 如果遇到了 img 或 css 和 js等引用外部文件的标签,那么浏览器会根据指定的 url 再次发起一个新的 http 请求,去把这个文件拉取回来,值得一提的是,对于同一个域名下的下载过程来说,浏览器一般允许的并发请求是有限的,通常控制在两个左右,所以如果有很多的图片的话,一般出于优化的目的,都会把这些图片使用一台静态文件的服务器来保存起来,负责响应,从而减少主服务器的压力。请求过程是异步的,并不会影响html文档进行加载。
- 但是当文档加载过程遇到了由 script 标签包起来的 js 动态脚本代码或js文件,那么会把代码送到 js 引擎里面去跑。html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。
- 解析
解析文档是指将文档转化成为有意义的结构,也就是可让代码理解和使用的结构。解析得到的结果通常是代表了文档结构的节点树,它称作解析树或者语法树,也就是DOM树(抽象的逻辑树)。如下图:
css解析是指将css文件解析为样式表对象。如下图:
js解析是文件在加载的同时也进行解析
如果想深入如何解析的话可以看浏览器的工作原理:新式网络浏览器幕后揭秘这篇文章
- 渲染
即为构建渲染树的过程,就是将DOM树进行可视化表示。构建这棵树是为了以正确的顺序绘制文档内容。
用DOM树和CSS样式表构建render树,,这个才是真正的用于渲染到页面上的一个一个的矩形框的树,网页渲染是浏览器最复杂、最核心的功能,对于 render 树上每一个框,需要确定他的 x y 坐标,尺寸,边框,字体,形态,等等诸多方面的东西。等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上。这个过程比较复杂,涉及到两个概念: reflow(回流)和repain(重绘)。
需要说明的是,加载、解析(构建 dom 树)、渲染(构建 render 树,绘制)。这三个步骤在执行的过程中并不是严格按照先后顺序进行的。浏览器在解析html文件时,会”自上而下“加载数据,并在加载过程中进行解析渲染。
即为了加快速度,提高效率,让用户不要等那么久,浏览器在加载数据的同时,构建 dom 树,并构建 render 树,同时将其显示在页面上。如果遇到外部链接,异步请求数据,在得到数据后,循环执行上述步骤。
关于回流和重绘
Reflow,也称作Layout:DOM节点中的各个元素都是以盒模型的形式存在,这些都需要浏览器去计算其位置和大小等,这个过程称为relow;
Repaint:元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就OK了,这个过程称为Repaint。
页面在首次加载时必然会经历reflow和repain。reflow和repain过程是非常消耗性能的,尤其是在移动设备上,它会破坏用户体验,有时会造成页面卡顿。所以我们应该尽可能少的减少reflow和repain。
回流的成本比重绘高;回流一定引起重绘,重绘不一定引起回流
引起回流和重绘的动作:
- 网页初始化的时候
- 增加、删除、修改DOM结点时
- 移动DOM的位置,或是搞个动画的时候,一些js在操作DOM树时
- Resize窗口的时候(移动端没有这个问题),或是滚动的时候
引起重绘
- 内容发生变化
- 修改CSS样式的时候
- 修改网页的默认字体时
关于加载过程中遇到js
当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。因为JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。所以我明平时的代码中,js是放在html文档末尾的。
JS的解析是由浏览器中的JS解析引擎完成的,比如谷歌的是V8。JS是单线程运行,也就是说,在同一个时间内只能做一件事,所有的任务都需要排队,前一个任务结束,后一个任务才能开始。但是又存在某些任务比较耗时,如IO读写等,所以需要一种机制可以先执行排在后面的任务,这就是:同步任务(synchronous)和异步任务(asynchronous)。
JS的执行机制就可以看做是一个主线程加上一个任务队列(task queue)。同步任务就是放在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务在主线程上执行,形成一个执行栈;异步任务有了运行结果就会在任务队列中放置一个事件;脚本运行时先依次运行执行栈,然后会从任务队列里提取事件,运行任务队列中的任务,这个过程是不断重复的,所以又叫做事件循环(Event loop)。
六、绘制网页
浏览器根据 HTML 和 CSS 计算得到渲染树,最终绘制到屏幕上
总结 :
- 在浏览器的地址栏中敲入了url (url地址写法;http,https区别)
- 域名解析(域名到IP的映射;根域,顶域,二级域,权限域;)
- 查看浏览器缓存(强缓存,协商缓存)
- 服务器处理请求(TCP连接;http协议,头文件,状态码)
- 浏览器处理(加载,解析,渲染;重排重绘;js线程)
- 绘制网页