前言
了解了浏览器的 导航流程,就可以来回答 “从输入 url
按下回车到页面展示的过程中发生了什么?”这道经典问题的前半部分了,即 从用户发出 URL 请求到页面开始解析的这个过程,也就是 网络请求部分。
我们知道,现在的 Chrome 浏览器是 多进程架构,上面的这道经典问题涉及到的进程有浏览器进程、网络进程和渲染进程,先来简单回顾一下这三个进程的主要职责:
- 浏览器进程:主要负责页面显示、用户交互、子进程管理、文件存储等功能。
- 网络进程:主要为浏览器进程和渲染进程提供网络请求资源功能。
- 渲染进程:核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页。
接下来就 来看看浏览器是怎么通过进程之间的协作来完成网络请求的功能吧!
用户输入
流程从用户在地址栏输入查询关键字开始:
- 用户在地址栏输入关键字,浏览器进程 会判断是请求
url
还是搜索内容- 如果是搜索内容,则浏览器会使用默认的搜索引擎,合成带有搜索内容的
url
- 如果是请求的
url
,则根据规则判断是否完整,不完整则根据规则合成完整的url
- 如果是搜索内容,则浏览器会使用默认的搜索引擎,合成带有搜索内容的
- 按下回车,浏览器进入加载状态
- 在流程继续之前,浏览器还有一个
beforeunload
事件可以执行,该事件可以做一些数据清理操作,还可以中断流程,取消导航; - 如果没有
beforeunload
事件或同意继续后续的操作,则流程继续,浏览器进入加载状态; - 但页面还是之前的内容,要到 提交文档 阶段才会被替换新的内容。
- 在流程继续之前,浏览器还有一个
例如,下图原来的页面是 https://www.npmjs.com/package/egg
的内容,我在搜索框输入 https://www.npmjs.com/package/koa
后按下回车,浏览器便进入了加载状态(左上角的图标开始转圈圈、左下角说正在等待响应),但是页面还是之前 egg
的内容。
- 接下来是进入 网络资源请求过程,浏览器进程 通过进程间通信(IPC)把
url
请求交给 网络进程。
网络资源请求
查找缓存
上面 浏览器进程 已经把 url
请求的活交给了 网络进程,那么接下来具体的请求流程是怎么样的呢?
网络进程并不会直接发起网络请求,因为 没有请求的请求,才是最快的请求。
- 按照 浏览器缓存策略,网络进程会去检查该资源 是否允许缓存(
Cache-Control
),是否在本地缓存了该资源(缓存位置依次查找) - 如果有缓存资源则网络进程直接返回资源给浏览器进程,网络请求结束
- 如果没有找到资源或者需要验证资源是否有效,则会 真正进入网络请求流程
缓存是一个大课题,会在后面性能优化的章节再详细整理。
DNS 解析
网络请求的 第一步是要拿到请求的服务器 IP 地址,因为 网络请求过程归根结底是一个计算机向另一个计算机请求资源,需要通过 IP 地址建立连接的。
一般情况下,用户看到的用到的是 域名,是一串用 .
分隔的多个单词,像掘金是 juejin.cn
、淘宝是 www.taobao.com
、百度是 www.baidu.com
,这个域名是极其重要的,它是一个网站的入口,可以说是拥有了一个好域名就拥有了一个好梦想。听说 FACEBOOK 一开始的域名是 thefacebook.com
,后来融资了才花 20 万美金买回 facebook.com
的域名,要是穿越回到过去,屯一波域名都可以成为亿万富翁,哈哈。
回到正题,一个域名可以对应多个 IP 地址,它可以是源服务器的 IP 地址,也可以是 CDN 分发的 IP 地址,还可以是迁移服务器时的一些临时 IP 地址,我们可以用域名系统做很多有趣的事情。
为了拿到正确的 IP 地址,它有一套自己的解析系统,这个系统就是 DNS 系统,如果想更多的了解 DNS 系统,可以去看我之前写过的 DNS域名系统有哪些门道? 。
那么接下来继续 网络请求流程:
- 如果用户输入的就是 IP 地址,则直接进入 TCP 连接阶段
- 如果用户输入的是域名,则需要进行 DNS 解析,得到服务器的 IP 地址再建立 TCP 连接
- DNS 也是有缓存的,它的缓存查找过程是浏览器缓存->操作系统缓存->Hosts文件->非权威域名服务器 -> 根域名服务器 -> 顶级域名服务器 -> 权威域名服务器
TCP 连接
网络进程拿到 IP 地址之后则进入 TCP 连接阶段。
- 请求进入 TCP 队列,单个域名是有 TCP 连接限制(最多6个)的,超出限制需要排队。
- 浏览器和服务端通过三次握手建立 TCP 连接
- 客户端向服务端发送连接请求报文
- 服务端收到连接请求报文段后,如果同意连接,则会发送一个应答
- 当客户端收到连接同意的应答后,要向服务端发送一个确认报文
- 如果请求协议是 HTTPS,TCP 连接后还要建立 TLS 连接(安全地交换对称密钥)
发出 HTTP 请求
建立连接后,网络进程正式发出 HTTP 请求。
- 浏览器端会构建请求行、请求头等信息,并把和该域名相关的 Cookie 等数据附加到请求头中,然后向服务器发送请求信息
- 请求行简要地描述了客户端想要如何操作服务器端的资源,由请求方法、请求目标、版本号三部分构成
- 头部字段是
key-value
的形式,key
和value
之间用:
分隔,用CRLF
换行,表示字段结束。
服务器响应返回数据
- 服务器接收到请求信息后,会根据请求信息 生成响应数据返回(包括响应行、响应头和响应体等信息)
- 状态行代表服务器响应的状态,同样由三部分构成:版本号、状态码、原因
- 服务器返回信息给网络进程,网络进程接收后开始解析:
- 解析响应头:
- 如果发现返回状态码是
301
或302
,则说明服务器需要浏览器 重定向 到其他url
,网络进程会从响应头的Location
字段里面读取重定向的地址,然后再发起新的网络请求; - 如果状态码是
200
,那么表示浏览器可以继续处理该请求。
- 如果发现返回状态码是
- 解析响应数据类型:通过
Content-Type
头字段区分数据类型。- 如果
Content-Type
字段的值被浏览器判断为下载类型,那么该请求会被提交给浏览器的下载管理器,同时该url
请求的导航流程就此结束 - 如果是
HTML
类型,那么浏览器则会继续进行导航流程;
- 如果
- 解析响应头:
网络请求拿到 HTML 类型的数据后继续导航流程,由于 Chrome 的页面渲染是运行在渲染进程中的,所以接下来就需要准备 渲染进程 了。
准备渲染进程
- 默认情况下,Chrome 会为每个页面分配一个渲染进程
- 通常情况下,打开新的页面都会使用单独的渲染进程;
- 但是如果从 A 页面打开 B 页面,且 A 和 B 都属于同一站点(拥有相同的协议和根域名)的话,那么 B 页面会复用 A 页面的渲染进程;如果是其他情况,浏览器进程则会为 B 创建一个新的渲染进程。
- 渲染进程准备好之后,还不能立即进入文档解析状态,因为此时的文档数据还在 网络进程 中,并没有提交给渲染进程,所以下一步就进入了 提交文档 阶段。
提交文档
提交文档,就是指浏览器进程将网络进程接收到的 HTML 数据提交给渲染进程。
具体流程是:
- 首先当 浏览器进程 接收到 网络进程 的响应数据之后,便向 渲染进程 发起“提交文档”的消息;
- 渲染进程 接收到“提交文档”的消息后,会 和网络进程建立传输数据的“管道”;
- 等文档数据传输完成之后,渲染进程会返回“确认提交”的消息给浏览器进程;
- 浏览器进程 在收到“确认提交”的消息后,会更新浏览器界面状态,包括了安全状态、地址栏的
url
、前进后退的历史状态,并更新 Web 页面。
这也解释了为什么在浏览器的地址栏里面输入了一个地址后,之前的页面没有立马消失,而是要加载一会儿才会更新页面。
进入渲染阶段
提交文档后,渲染进程 便开始页面解析和子资源加载了。
一旦页面生成完成,渲染进程 会发送一个消息给 浏览器进程,浏览器接收到消息后,会停止标签图标上的加载动画。
导航流程总结
以上就是 从用户发出 URL 请求到页面开始解析的过程 即 导航流程 了。
简而言之,就是下面这样的流程:
- 浏览器进程把用户输入的
url
组装成完整的url
后交给网络进程; - 网络进程通过 DNS 解析拿到 IP 地址与服务端建立 TCP 连接,然后发出 HTTP 请求,在收到服务端响应返回的数据后开始解析处理;
- 网络进程收到 HTML 类型的数据后,通过提交文档把数据提交给渲染进程,准备进入页面渲染阶段。