从输入 URL 到页面展示到底发生了什么
本文的目的是通过输入 url 之后发生的事情来做知识的总结和扩展。所以文章可能会比较发散。
总结的过程大致如下:
文章目录
1、URL 解析
当我们开始在浏览器地址栏中输入网址的时候,浏览器其实就已经在智能的匹配可能的 url 了,它会从历史记录、书签等地方找到已经输入的字符串可能对应的 url,然后给出智能提示,让你可以不全 url 地址。对于 Chrome 浏览器来说,它甚至会直接从缓存中把网页展示出来,也就是说,你还没有按下 Enter 键,页面就出来了。
当我们输入完成 URL 并按下 Enter 键后,浏览器首先要解析输入的 URL,确定要访问的是哪个网站。该过程包括协议解析、主机名解析、端口解析、路径解析等。
比如,对于 URL“https://www.hi-ruofei.com/archives/161.html”来说,协议是“https”,主机名是”www.hi-ruofei.com”,端口是 443,路径是”/archives/161.html”。
2、DNS 查询
浏览器会将主机名(www.hi-ruofei.com)解析成 IP 地址,如果本地已经缓存了 DNS 记录,这一过程会很快。如果没有,那么请求就会发送到配置的 DNS 服务器,通常就是你的网络服务提供商处,比如中国电信、中国移动。之后 DNS 服务器会查找相应的记录并返回给浏览器。如果 DNS 服务器没有缓存要查询的记录,DNS 服务器还要向 DNS 根服务器查询。
3、建立 TCP 连接
一旦浏览器获取了服务器的 IP 地址,它就会向服务器发起 TCP 连接。这个过程通常被称为“三次握手”。这个过程的目的是为了在浏览器和服务器之间建立一个可靠的连接,以便于数据的传输。
4、发送 HTTP 请求
浏览器通过 TCP 连接向服务器发送 HTTP 请求。这个请求包括请求行(例如 GET /index.html HTTP/1.1)、请求头(例如 User-Agent, Accept 等)和请求体(如果是 POST 请求的话)。
5、服务器处理请求并返回 HTTP 响应
服务器接收到请求后,会根据请求的 URL 和方法,处理请求并生成响应,然后通过 TCP 连接返回给浏览器。这个响应包括响应状态行(例如 HTTP/1.1 200 OK)、响应头(例如 Content-Type, Content-Length 等)和响应体(即网页的 HTML 内容)。
6、浏览器解析 HTML
浏览器接收到 HTTP 响应后,会开始解析 HTML,构建 DOM 树。在这个过程中,如果遇到 CSS、JavaScript、图片等资源的链接,浏览器会再次发起 HTTP 请求获取这些资源。
7、浏览器渲染页面
浏览器在构建 DOM 树的同时,会构建 CSSOM 树(CSS Object Model)。然后浏览器会将 DOM 树和 CSSOM 树合并成一个渲染树(Render Tree),并根据这个渲染树来计算每个节点的布局(Layout),然后绘制(Paint)出页面。如果遇到 JavaScript,浏览器会执行 JavaScript 代码,可能会修改 DOM 树和 CSSOM 树,这可能会导致重新布局和绘制。
8、关闭 TCP 连接
- 最后,浏览器会关闭 TCP 连接,进行四次挥手。这个过程是为了优雅地关闭连接,确保所有的数据都已经被接收。
这就是从输入 URL 到页面展示的整个过程,我们结合这个过程来扩展一些知识点。
1. 什么是 DNS?
DNS,全称为Domain Name System(域名系统),是互联网的一项核心服务。它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网,而不需要记住能够被机器直接读取的 IP 数串。
在互联网上,每个设备都有一个唯一的 IP 地址,就像每个人都有一个唯一的电话号码一样。IP 地址由一串数字组成,比如:192.168.1.1,这对我们来说不容易记忆。因此,我们使用域名来代替 IP 地址。我们可以把 DNS 看做是一个电话本,比如要找 hi-ruofei.com 这个域名,翻翻电话本,就知道它的 ip 是 167.23.10.2。
2. TCP 三次握手
- SYN:客户端发送一个带有 SYN(Synchronize Sequence Numbers)标志的数据包给服务器,以请求建立连接。这个数据包还包含一个随机的序列号 A。假设你(客户端)打电话给一个朋友(服务器),这次握手就表示你拨打朋友的电话号码(发送 SYN 请求)。
- SYN-ACK:服务器接收到客户端的 SYN 请求后,会发送一个带有 SYN 和 ACK (Acknowledgement)标志的数据包给客户端。这个数据包包含一个自己的随机序列号 B,以及对客户端序列号 A 的确认(即 A+1)。可以这样理解——你的朋友接到电话后说:“你好,我听到你了。”(发送 SYN-ACK 响应),这表示他的电话是通的,他能听到你的声音。
- ACK:客户端接收到服务器的 SYN-ACK 数据包后,会发送一个带有 ACK 标志的数据包给服务器,确认服务器的序列号 B(即 B+1)。至此,一个TCP连接就建立起来了。当你听到朋友的回应后,你说:“我也听到你了。”(发送 ACK 确认),这表示你的电话也是通的,你也能听到他的声音。
为什么要这样设计呢?主要有两点:
- 可靠性:通过三次握手,双方都能确认对方的发送和接收能力,确保数据能够正确无误地在两者之间传输。
- 防止旧的连接请求报文突然出现在网络中:如果不使用三次握手,那么只要服务器接收到请求,就直接建立连接。但是,如果这个请求是一个旧的请求,比如说是因为网络延迟,那么服务器就会错误地建立一个不存在的连接,浪费资源。通过三次握手,可以防止这种情况发生,因为客户端会在最后一次握手中确认是否真的要建立连接。
3. TCP 四次挥手
- FIN:当客户端决定关闭连接时,它会发送一个带有 FIN(Finish)标志的数据包给服务器,表示客户端已经没有数据要发送了。假设你(客户端)正在和一个朋友(服务器)通电话,这次挥手就表示你告诉朋友你要挂电话了(发送 FIN 请求)。
- ACK:服务器接收到客户端的 FIN 数据包后,会发送一个带有 ACK(Acknowledgement)标志的数据包给客户端,表示服务器已经接收到了客户端的关闭请求,但可能还有数据需要处理和发送。你的朋友听到你要挂电话,他说:“我知道了,但我还有几句话要说。”(发送 ACK 响应),这表示他已经知道你要挂电话,但他还有一些话要说。
- FIN:当服务器处理完所有数据并准备好关闭连接时,它会发送一个带有FIN标志的数据包给客户端。你的朋友说完他的话后,他说:“我说完了,我们可以挂电话了。”(发送 FIN 请求)。
- ACK:客户端接收到服务器的 FIN 数据包后,会发送一个带有 ACK 标志的数据包给服务器,表示客户端已经接收到了服务器的关闭请求,并确认服务器可以关闭连接。至此,TCP连接就被成功关闭了。你听到朋友的话后,你说:“好的,我们挂电话吧。”(发送 ACK 确认),这表示你已经知道朋友已经说完话,同意挂电话。
为什么要这样设计呢?而且,为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
首先,这样设计的原因主要是因为 TCP 是一个全双工协议,这意味着客户端和服务器可以同时发送和接收数据。因此,关闭连接时,需要双方都确认对方已经没有数据要发送,这就需要四次挥手。
在建立连接时,只需要确认双方的发送和接收能力,因此只需要三次握手即可;而在关闭连接时,除了确认双方的发送和接收能力,还需要确认双方都已经没有数据要发送,这就需要额外的一次交互,也就是四次挥手。
从输入 URL 到页面展示其实还涉及到很多非常复杂的技术和协议,这里只介绍了 DNS 的概念和 TCP 三次握手以及 TCP 的四次挥手