1. 用户输入内容后,回车。
2. 浏览器地址栏会判断用户输入的是搜索内容还是请求的URL。
- 当协议或主机名不合法时, 就会判断是搜索内容,地址栏会使用浏览器默认的搜索引擎,来合成新的带搜索关键字的 URL。
- 如果是请求的URL,那么地址栏会根据规则,把这段内容加上协议,合成为完整的 URL,如输入 juejin.cn, 会合成为完整的URL:juejin.cn/ 。
(思考:浏览器是怎么知道应该给url加上http 还是 https?)
浏览器厂商们提出了HSTS Preload List方案:内置一份可以定期更新的列表,对于列表中的域名,即使用户之前没有访问过,也会使用HTTPS协议。HSTS(HTTP Strict Transport Security) 简单来说就是由浏览器进行http向https的重定向。如果不使用HSTS,当用户在浏览器中输入网址时没有加https,浏览器会默认使用http访问,所以对于https站点,通常会在服务端进行http至https的重定向。如果用了HSTS,就可以减少服务端的这次重定向。参考
3. 浏览器进程会通过进程间通信(IPC)把 URL 请求发送至网络进程,网络进程会查找本地缓存是否缓存了该资源。
- 如果有缓存,则将缓存的资源返回给浏览器进程。
- 如果没有缓存或者缓存已过期,那么直接进入网络请求流程。
(思考:怎么判断有没有缓存?如何查找缓存?)
- 当资源第一次被访问的时候,http返回200的状态码,并在头部携带上当前资源的一些描述信息
Last-Modified // 指示最后修改的时间
Etag // 指示资源的状态唯一标识
// 到了HTTP/1.1,Expires已经被Cache-Control替代,原因在于Expires控制缓存的原理是使用客户端的时间与服务端返回的时间做对比,如果客户端与服务端的时间由于某些原因(时区不同;客户端和服务端有一方的时间不准确)发生误差,那么强制缓存直接失效
Cache-Control // 在HTTP/1.1中,Cache-Control是最重要的规则,主要用于控制网页缓存
Expires // 在HTTP/1.0中,Expires 是控制网页缓存的字段,指示资源在浏览器缓存中的过期时间
复制代码
- 接着浏览器将该结果和缓存标识存入浏览器缓存中(浏览器的缓存存放在哪里?)
Cache-Control: public //所有内容都将被缓存(客户端和代理服务器都可缓存)
Cache-Control: private //所有内容只有客户端可以缓存,Cache-Control的默认取值
Cache-Control: no-cache //客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
Cache-Control: no-store //所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
Cache-Control: max-age=xxx //(xxx is numeric):缓存内容将在xxx秒后失效
复制代码
- 当第二次请求该文件时,浏览器会先检查是否存在该文件的缓存结果和缓存标识。 情况1: 如果不存在该缓存结果和缓存标识,强制缓存失效,则直接向服务器发起请求。
情况2: 如果存在该缓存结果和缓存标识,且该结果没有还没有失效,强制缓存生效,直接返回该结果。
情况3: 如果存在该缓存结果和缓存标识,但是结果已经失效,强制缓存失效,则使用协商缓存。协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程。 参考强缓存和协商缓存
// 协商缓存的字段 ,Etag/If-None-Match 优先级高于 Last-Modified/If-Modified-Since,同时存在则只有Etag / If-None-Match生效。
Last-Modified // 该资源文件在服务器最后被修改的时间,第一次请求时服务器会返回这个字段
// 若服务器的资源最后被修改时间大于If-Modified-Since的字段值,则重新返回资源,状态码为200;否则则返回304,代表资源无更新,可继续使用缓存文件
If-Modified-Since // 告诉服务器该资源上次请求返回的最后被修改时间,它的值是Last-Modified的值
Etag //当前资源文件的一个唯一标识(由服务器生成),第一次请求时服务器会返回这个字段
// 根据If-None-Match的字段值与该资源在服务器的Etag值做对比,一致则返回304,代表资源无更新,继续使用缓存文件;不一致则重新返回资源文件,状态码为200
If-None-Match // 告诉服务器该资源上次请求返回的唯一标识值,它的值是Etag的值
复制代码
4. 在真正发起请求之前,还需要进行DNS解析,解析出URL背后的ip地址是什么。要进行 DNS 解析来获取请求域名的服务器 IP 地址。如果请求协议是 HTTPS,那么还需要建立 TLS 连接。
(思考:DNS 是什么?如何查找ip地址?)
DNS是域名系统,它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。 DNS 协议提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。DNS 是一个网络服务器,我们的域名解析简单来说就是在 DNS 上记录一条信息记录。例如 baidu.com 220.114.23.56(服务器外网IP地址)80(服务器端口号)
-
浏览器会先查找本地hosts文件是否有这个网址映射关系,有就调用ip地址映射,完成域名解析。
-
如果没有找到,则在操作系统缓存中查找本地DNS解析器缓存,有则返回
-
如果没有找到,则在路由器缓存中进行查找,有则返回
-
如果没有找到,则按ISP(运营商)DNS缓存、根域名服务器、顶级域名服务器、主域名服务器的顺序,逐步读取缓存,直到拿到IP地址
5. 拿到IP地址后,利用 IP 地址和服务器建立 TCP 连接。
-
连接建立之后,浏览器端会构建请求行、请求头等信息,并把和该域名相关的 Cookie 等数据附加到请求头中,然后向服务器发送构建的请求信息。
-
服务器接收到请求信息后,会根据请求信息生成响应数据(包括响应行、响应头和响应体等信息),并发给网络进程。等网络进程接收了响应行和响应头之后,就开始解析响应头的内容了。
(思考: 如何建立TCP 连接?为什么是3次握手?)参考1 参考2
1、建立连接时,客户端发送SYN包(SYN=i)到服务器,并进入到SYN-SEND状态,等待服务器确认
2、服务器收到SYN包,必须确认客户的SYN(ack=i+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器进入SYN-RECV状态
3、客户端收到服务器的SYN+ACK包,向服务器发送确认报ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手,客户端与服务器开始传送数据。
为什么必须三次握手:就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立,是为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
6. 在接收到服务器返回的响应头后,网络进程开始解析响应头。
- 如果发现返回的状态码是 301 或者 302,那么说明服务器需要浏览器重定向到其他 URL。这时网络进程会从响应头的 Location 字段里面读取重定向的地址,然后再发起新的 HTTP 或者 HTTPS 请求,一切又重头开始了。
- 如果发现响应行是 200,那么表示浏览器可以继续处理该请求。
7. 根据服务器响应应头的Content-Type来判断是什么类型进行响应数据类型处理。
- 如果响应头中的 Content-type 字段的值是 text/html,服务器返回的数据就是 HTML 格式,浏览器会按照HTML类型来处理请求,浏览器则会继续进行导航流程。
- 如果响应头中的Content-Type 的值是 application/octet-stream,显示数据是字节流类型的,通常情况下,浏览器会按照字节流类型来处理该请求,该请求会被提交给浏览器的下载管理器,同时该 URL 请求的导航流程就此结束。
- 如果服务器配置 Content-Type 不正确,比如将 text/html 类型配置成 application/octet-stream 类型,那么浏览器可能会曲解文件内容,比如会将一个本来是用来展示的页面,变成了一个下载文件。
8. 浏览器为页面准备渲染进程。
- 通常情况下,打开新的页面都会使用单独的渲染进程。
- 如果从 A 页面打开 B 页面,且 A 和 B 都属于同一站点的话,那么 B 页面复用 A 页面的渲染进程;如果是其他情况,浏览器进程则会为 B 创建一个新的渲染进程。
9. 浏览器进程通知渲染进程去接收网络进程接收到的 HTML 数据
- 当浏览器进程接收到网络进程的响应头数据之后,便向渲染进程发起“提交文档”的消息。
- 渲染进程接收到“提交文档”的消息后,会和网络进程建立传输数据的“管道”。
- 等文档数据传输完成之后,渲染进程会返回“确认提交”的消息给浏览器进程。
- 浏览器进程在收到“确认提交”的消息后,会更新浏览器界面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 Web 页面。
10.渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构
(思考:html 如何 变成 DOM?)
- 根据 HTML 的内容,将标签按照结构解析成为 DOM 树,DOM 树解析的过程是一个深度优先遍历。即先构建当前节点的所有子节点,再构建下一个兄弟节点。
- 在读取 HTML 文档,构建 DOM 树的过程中,若遇到 script 标签,则 DOM 树的构建会暂停,直至脚本执行完毕。
11.渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
- 把 CSS 转换为浏览器能够理解的结构
- 转换样式表中的属性值,使其标准化
- 计算出 DOM 树中每个节点的具体样式
12.创建布局树,并计算元素的布局信息
13.对布局树进行分层,并生成分层树
- 如果有一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树。页面的本质就是若干个图层堆叠而成的图像。
- 并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。
- 拥有层叠上下文属性的元素会被提升为单独的一层。
- 需要剪裁(clip)的地方也会被创建为图层。
14.为每个图层生成绘制列表,并将其提交到合成线程
渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。
15.合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图
- 绘制操作是由渲染引擎中的合成线程来完成的。
- 当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程。
- 合成线程会将图层划分为图块(tile)。
- 合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。
- 栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。
- GPU 操作是运行在 GPU 进程中,最终生成位图的操作是在 GPU 中完成的。
- 渲染进程把生成图块的指令发送给 GPU,然后在 GPU 中执行生成图块的位图,并保存在 GPU 的内存中。
16.合成线程发送绘制图块命令 DrawQuad 给浏览器进程
- 一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。
17.浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上
- 浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。