了解浏览器如何工作

浏览器是网络世界里至关重要的工具之一。下图是一个用户使用浏览器的基本用户场景:

但浏览器究竟是如何能够做到这些的呢?理解浏览器的工作流程和原理,所谓知其然而知其所以然,一定会对我们的工作有所裨益。

首先我们了解下常用的浏览器和浏览器的组成部分。

常用浏览器

常用的桌面浏览器有Chrome,Internet Explorer, Firefox,Safari, Opera。

常用的移动设备浏览器: Android浏览器,iPhone浏览器,Chrome,Opera Mini,Opera Mobile, UC浏览器等等。

浏览器组成

浏览器主要分成以下7部分:

1. UI – The User Interface

其实就是浏览器呈现给用户的所有用户接口。包括地址栏,前进/后退/刷新按钮,书签菜单,历史记录等等。

2. 浏览器引擎 – The Browser Engine

统领UI和渲染引擎,在他们之间传递数据和指令。

3. 渲染引擎 – The Rendering Engine

负责显示请求的内容, 可能是HTML,图片,PDF等,渲染引擎会对这些内容进行解析,然后将解析后的内容显示在浏览器窗口。

不同的浏览器使用不同的渲染引擎:

浏览器

渲染引擎(开发语言)

Chrome

Blink (c++)

Opera

Blink (c++)

Safari

Webkit (c++)

FireFox

Gecko (c++)

Edge

EdgeHTML (c++)

IE

Trident (c++)

WebKit是一个开源渲染引擎,其刚开始只是一个用于Linux平台的引擎,苹果公司对其进行了修改,使其可以用与macOS和Windows平台。

4. 网络 – Networking

用于网络调用(针对于平台无关的统一接口,在不同的平台上使用不同的底层实现),比如HTTP请求。

5. JavaScript解释器 – JavaScript Interpreter

准确的说,应该说是JavaScript引擎,JavaScript引擎是一个子系统,用于将JS代码解析成机器码然后执行。Google V8引擎是最流行的JavaScript引擎。而不同的浏览器使用的JavaScript引擎也不尽相同:

浏览器

脚本引擎(开发语言)

Chrome

Google V8 (c++)

Opera

Google V8 (c++)

Safari

JavaScript Core (nitro)

FireFox

SpiderMonkey (c/c++)

Edge

Chakra JavaScript Engine (c++)

IE

Chakra JScript Engine (c++)

6. UI后端 – UI Backend

用于绘制基本小部件,比如组合框和窗口。UI后端会提供与平台无关的通用接口。其底层会使用操作系统的用户接口方法。

7. 数据存储 – Data Storage

这是数据持久层。浏览器需要保存各种各样的本地数据,比如cookies.浏览器也支持其它多种存储机制,比如localStorage,sessionStorage, AppCache, IndexedDB,WebSQL等。

那接下来我们来看看浏览器的工作流程。

浏览器工作流程

1. 处理地址栏输入

  • 如果已有打开的页面,unload当前页面。
  • 解析地址栏输入。以Chrome为例,会根据相应的规则,将地址栏输入解析成搜索请求或者URI请求。如果是搜索,解析处搜索关键字,然后与搜索引擎地址组装成一个URI请求;否则,浏览器就会将地址与相关协议(HTTP,HTTPs等)组装成一个URI请求。
  • 在触发DNS Lookup之前,浏览器会首先确认缓存中是否存在域名的IP地址。浏览器会依次检查浏览器缓存,操作系统缓存,路由缓存和ISP DNS缓存,如果在缓存中找到了域名的IP地址,那么就可以直接使用改IP地址发起网络请求;反之,DNS Lookup就会发生。

需要指出的是:

  • 并非URI不同,域名就不同,事实上不同的URI可以有相同的域名,也就是所谓相同的源,这个可以参考Web请求的header的origin字段。
  • 缓存中不光会有关于域名的信息,也包括网址重定向信息和离线网页信息等。
  • 如果缓存中有网址重定向信息,那么就会向重定向的网址发出请求;如果缓存中有离线网页信息,那么会直接打开离线网页(本文不会过多在意细节)。

  【概念】:

  • 永久重定向(状态码301),即原域名已经永久修改成新域名,浏览器会缓存永久重定向的DNS解析记录。
  • 临时重定向(状态码302),浏览器不会缓存当前域名的解析记录。

  

2. DNS Lookup

DNS(Domain Name System)是域名系统, 可将域名解析成对应的IP地址,从而用户可以通过域名在英特网上访问特定Web 服务器提供的在线信息或服务。

当浏览器想要访问某个域名时,会首先检查缓存,如果缓存已经保存了对应的IP地址,那么DNS Lookup就不会发生;反之,下图的DNS Lookup流程会被触发:

第一步: 浏览器无法得知输入域名的IP地址,所以向DNS Resolver发起一个   DNS递归查询。这意味着DNS Resolver必须完成递归查询(recursive query),并返回给查询发起者。对于大多数用户来说,DNS Resolver是由Internet服务供应商(ISP)提供,或者使用开源DNS,比如Google DNS(8.8.8.8)和OpenDNS(208.67.222.222)。当然也可以是本地域名服务器(Local Domain Server)。

第二步:DNS Resolver本身并没有保存域名和IP地址的对应信息,所以向DNS根服务器(Root server)发起迭代查询(Iterative query),

第三步:DNS根服务器中保存了所有TLD Server的地址。DNS根服务器将与域名example.com 匹配的TLD Server(.com)的地址返回给DNS Resolver。TLD server也就是顶级域名服务器,可以是.com, .edu, .org, .net等。

第四步:DNS Resolver向.com TDL Server发起发起迭代查询。

第五步:TDL Server将example.com的Name server的IP地址返回给DNS Resolver。

第六步:DNS Resolver向example.com的Name server发起迭代查询。

第七步:Name server将example.com的IP地址返回给DNS Resolver。

第八步:DNS Resolver将example.com的IP地址返回给浏览器。

整个DNS查询过程可以看作: 我们委托朋友(DNS Resolver)帮助我们完成查询,而朋友通过递归查询各级目录,最终获得域名的IP地址,并返回给我们。其中,Root Server是根目录,查询根目录获取到次级目录com的位置;然后通过次级目录(也就是TDL Server),获取到最终目录项example.com的位置;最后从example.com(也就是Name server)获取到IP地址。

3. 建立TCP连接

当IP地址被确认后,浏览器会根据这个IP,通过TCP三次握手(TCP three-way handshake)的方式,和服务器建立连接。

所谓TCP三次握手:

第一次: 浏览器发送一个TCP 同步包(SYNchronize package)给服务器,等待确认。

第二次: 服务器收到SYN包,并返回一个同步确认包(SYNchronize-ACKnowledgement package)。

第三次: 浏览器收到服务器的SYN-ACK,向服务器发送一个确认包(ACKnowledgement package)。当服务器收到ACK后,TCP的socket连接就建立了。

如果要建立基于HTTPS的安全连接,那么TLS协商(TLS Negotiation)就会发生。浏览器和服务器需要更多次的握手。详情见下图:

      

4. 发送HTTP(S)请求       

      在TCP连接建立后,浏览器就会向相应的HTTP(S)服务器发送请求。

  HTTP请求信息由3部分组成:

1请求首行(Request Line)

  请求的第一行是方法URI协议/版本例如:GET /index.html HTTP/1.1

      “GET”代表请求方法(Method);

      “/index.html”表示URI;              

      “HTTP/1.1”代表协议和协议的版本。

  • 请求方法共有:CONNECT,DELETE,GET,HEAD,OPTIONS,POST,PUT,TRACE

2请求头(Request Header)

请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可 以声明浏览器所用的语言,请求正文的长度等。例如:

Host: www.baidu.com

Connection: keep-alive

sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"

Accept: application/json, text/javascript, */*; q=0.01

sec-ch-ua-mobile: ?0

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36

sec-ch-ua-platform: "macOS"

Sec-Fetch-Site: same-origin

Sec-Fetch-Mode: cors

Sec-Fetch-Dest: empty

Referer: https://www.baidu.com/

Accept-Encoding: gzip, deflate, br

Accept-Language: en

Cookie: BIDUPSID=49D61A297C62F47AD5C98B8CEDF00A05; PSTM=1615091511; __yjs_duid=1_20f12cca852c3dff005bbde1750e113f1622365350748;FG=1; BD_UPN=123253; MCITY=-233%3A;

3请求正文(Request Body)

请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:

username=test&password=test123

5. 服务器返回数据

当Web 服务器收到HTTP请求后,如果请求的页面在服务器中不存在,那么返回404错误;如果请求的页面已经被移至新的位置,那么301/302 redirect会被触发,那么浏览器需要重新以新的URI发出请求;如果服务器存在问题,无法返回数据,那么500(internal server error)会被返回;如果请求的页面存在,且符合访问规则,那么服务器就会返回请求的页面。

实际的情况,比我们提到的更多也更加复杂,我们就不一一赘述。如果想查看更多的HTTP状态码,可参考:https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

6. 浏览接收Response数据并关闭连接

浏览器接收到请求的数据后,TCL连接就会被关闭。关闭的过程就是四次挥手的过程:

第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。

第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。

第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。

第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

可参考下图去理解整个过程:

 

 

7. 浏览器解析Response数据并渲染

浏览器接受到response数据后,就会开始解析,如下图所示(不同的浏览器解析和渲染过程可能会略有不同,此处以Safari为例):

需要指出的是,一个网页可能需要多个HTTP请求,比如,主体的HTML文件是一个请求,而其相关的CSS,图片和JS文件等也需要一一请求。浏览器并不会等待所有的数据接收完成才开始解析,而只保证所有的数据最终都会被解析。

整个过程可描述为:

  • 解析HTML标记符号,开始生成DOM树
  • 解析CSS标记符号,开始生成CSSOM树
  • CSSOM树生成后,JS引擎会解析JS脚本,完成DOM树的创建
  • 合并DOM树和CSSOM树,生成渲染树
  • 基于渲染树和当前浏览器面板,计算页面元素的大小和相对位置
  • 将渲染树里的每个节点,结合Layout的计算结果,渲染引擎将渲染树转换成屏幕上实际的像素,即绘制内容。

【概念】:

  • DOM是Document Object Model的缩写,即文档对象模型。是W3C推荐的一种处理可扩展标志语言的一种标准编程接口。浏览器将机构化的文档HTML/XML读入,将文档中的每个标签建模成一个节点(Node),每个节点有各自的属性(名称,类型,内容等等),节点之间有层级关系(父亲,孩子,兄弟等),从而形成了树形结构。DOM提供的编程接口,支持访问,修改,添加和删除DOM树的节点和内容。
  • CSSOM树: 类此与DOM树,浏览器会便利CSS文件中所有的规则,创建一棵树,这棵树包含多个节点,基本CSS选择器,这些节点之间也有着层级关系,比如父亲,孩子,兄弟等等
  • Render树: 将DOM树和CSSOM合并后,就形成了Render树。
  • Layout: 当渲染树生成后,就会开始layout。Layout负责计算渲染树的每个节点在屏幕上的位置和维度。比如,不同的设备上的浏览器的宽度可能不同,那么,基本屏幕宽度的显示,Layout会得出不同的实际显示宽度。

下图是基于Navigation-Timing的流程图,仅作进一步学习之用。详情可以参考:Navigation Timing

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lemon2050

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值