我们在日常使用浏览器经常会在导航栏输入网页的url来访问对应的网页,于是我怀着好奇的心想去了解一下从输入了url到看到网页这个过程应该是什么样的。那么接下来就来说说过程是什么样吧。
一、浏览器
当你在浏览器中输入URL并请求访问一个网页时,浏览器会按照以下步骤进行缓存检查:
-
检查浏览器缓存:
- 浏览器首先会查看其本地缓存(Cache)中是否已经存储了该URL的资源。这包括HTML文档、CSS、JavaScript文件、图片等。
-
匹配请求:
-
如果缓存中找到了与请求URL匹配的资源,浏览器会检查该资源的有效性。有效性通常由以下几个因素决定:
- 过期时间:缓存的资源会有一个过期时间(Expires头或Cache-Control头中的max-age)。如果当前时间超过了过期时间,则该资源被视为过期。
- ETag或Last-Modified:浏览器可能还会使用ETag(实体标签)或Last-Modified(最后修改时间)来判断缓存内容是否仍然有效。浏览器会向服务器发送一个条件请求,询问资源是否更新。
-
-
使用缓存:
- 如果缓存资源仍然有效,浏览器将直接从缓存中读取并渲染该资源,而无需向服务器发起请求。
- 如果资源已过期或未找到,浏览器将向服务器发送新的请求以获取最新的资源。
-
更新缓存:
- 在获取新资源后,浏览器会将其存储到本地缓存中,以便下次请求时使用。
二、DNS域名解析
DNS解析将人类可读的域名(如www.example.com) 转换为机器可读的IP地址 (如192.168.0.1)的过程。具体步骤分为以下几步:
-
浏览器缓存:
- 当在浏览器缓存没有查找到对应的IP地址,才会进行下面步骤。
-
操作系统缓存:
- 每当我们访问过一个域名地址不仅浏览器会缓存对应的IP地址,操作系统也会有缓存。当在浏览器缓存中没有找到的话,就会在操作系统的DNS缓存中查找。如果在这里找到了有效记录,也会直接使用。
-
本地DNS服务器缓存
- 如果操作系统缓存也没有该域名的记录,那么请求会被发送到本地DNS服务器(通常是ISP提供的DNS服务器或用户手动配置的公共DNS服务器)。
- 本地DNS服务器会先检查其自身的缓存。
- 如果本地DNS服务器缓存中有该域名的有效记录,它会直接返回给用户的计算机。
-
根DNS服务器
- 如果本地DNS服务器也没有找到该域名的记录,它会向根DNS服务器发起查询。
- 根DNS服务器不会提供具体的IP地址,而是返回负责顶级域(TLD,如
.com
、.org
等)的权威DNS服务器的地址。
-
顶级域(TLD)DNS服务器
- 本地DNS服务器接着向TLD DNS服务器发出请求。
- TLD DNS服务器同样不会给出具体IP地址,而是指向负责次级域名(如
example.com
)的权威DNS服务器的地址。
-
权威DNS服务器
- 最后,本地DNS服务器向该权威DNS服务器发送请求。
- 权威DNS服务器保存有确切的IP地址信息,并将这些信息返回给本地DNS服务器。
-
响应传递
- 一旦本地DNS服务器得到了正确的IP地址,它会将结果返回给用户的计算机。
- 同时,为了提高效率,本地DNS服务器通常还会缓存这次查询的结果一段时间(基于TTL值,即生存时间)。
-
浏览器接收IP地址
- 用户的计算机接收到IP地址后,就可以使用这个IP地址与目标服务器建立TCP连接,并开始请求网页内容。
以上步骤我们可以用一张图片来更清晰的解释:
三、建立TCP连接
当浏览器获取到服务器的IP地址后,下一步就是与服务器建立TCP连接。TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。为了确保数据能够可靠地传输,TCP使用三次握手来建立连接。下面是建立TCP连接的具体步骤:
-
发送SYN报文段:
- 客户端向服务器发送一个SYN(Synchronize Sequence Numbers)报文段。
- 这个报文段包含一个随机的初始序列号(ISN),假设为
x
。 - SYN标志位被设置为1,表示这是一个连接请求。
-
接收SYN-ACK报文段:
- 服务器收到客户端的SYN报文段后,会回复一个SYN-ACK(Synchronize-Acknowledgment)报文段给客户端。
- 服务器选择一个随机的初始序列号,假设为
y
。 - 服务器在SYN-ACK报文段中设置自己的序列号为
y
,并确认客户端的序列号x
(通常确认号为x+1
)。 - SYN和ACK标志位都被设置为1,表示这是对连接请求的响应,并且已经准备好接收数据。
-
发送ACK报文段:
- 客户端收到服务器的SYN-ACK报文段后,会发送一个ACK(Acknowledgment)报文段给服务器。
- 客户端将确认号设置为
y+1
,以确认收到了服务器的SYN-ACK报文段。 - ACK标志位被设置为1,表示这是一个确认报文段。
经过这三次握手之后,TCP连接就建立了。此时,客户端和服务器都可以开始通过这个连接来发送和接收数据了。
具体细节
- 序列号:每个TCP报文段都有一个序列号,用于标识该报文段中的第一个字节在整个会话中的位置。序列号是保证数据传输顺序的重要机制。
- 确认号 :确认号表示期望从对方接收到的下一个字节的序列号。如果客户端发送了一个序列号为
x
的数据包,服务器应该回复一个确认号为x+1
的确认报文段,表示它已经成功接收到了所有小于x+1
的数据。 - 窗口大小:TCP报文段中还包含一个窗口大小字段,用于指示接收方可以接收多少数据而不需要等待进一步的确认。这有助于控制数据流的速度,防止网络拥塞。
对于HTTPS
对于使用HTTPS协议的情况,在完成三次握手建立TCP连接后,还需要进行SSL/TLS握手过程,以协商加密算法、交换密钥等安全相关的信息。只有在SSL/TLS握手完成后,才能开始加密的数据传输。
这样,通过TCP三次握手,客户端和服务器就能够建立起一个可靠的全双工通信通道。一旦TCP连接建立成功,浏览器就可以通过这个连接向服务器发送HTTP/HTTPS请求,获取网页资源。
四、发送HTTP/HTTPS请求
-
构建请求:
- 浏览器根据用户输入的URL构造一个HTTP或HTTPS请求。
- 请求包括请求行(如GET /index.html HTTP/1.1)、请求头(如Host: www.example.com, User-Agent, Accept等)以及可能的请求体(针对POST方法)。
-
发送请求:
- 通过已经建立的TCP连接,浏览器将HTTP/HTTPS请求发送给服务器。
五、服务器处理请求并返回响应
-
服务器接收请求:
- 服务器接收到客户端的请求后,会解析请求的内容。
-
处理请求:
- 根据请求的方法(GET、POST等)和路径,服务器执行相应的操作,如读取文件、查询数据库、运行脚本等。
-
生成响应:
- 服务器处理完请求后,生成一个HTTP响应。
- 响应包括状态码(如200 OK)、响应头(如Content-Type, Content-Length等)以及响应体(实际的网页内容或其他资源)。
-
发送响应:
- 服务器通过TCP连接将响应发送回客户端。
六、浏览器接收响应并渲染页面
-
接收响应:
- 浏览器接收到服务器的响应后,开始处理响应内容。
-
解析HTML文档:
- 如果响应是一个HTML文档,浏览器首先解析HTML代码,构建DOM树结构。
- 同时,如果HTML中包含CSS样式表链接,浏览器也会并行地下载这些CSS文件,并构建CSSOM树。
-
加载资源:
- 在解析HTML的过程中,遇到图片、脚本、外部样式表等其他类型资源时,浏览器会再次发起网络请求以获取这些资源。
- JavaScript脚本可能会阻塞后续内容的渲染直到它被完全执行完。
-
构建渲染树:
- 结合DOM树和CSSOM树的信息,浏览器创建出一个渲染树,用于确定每个元素应该如何显示。
-
布局计算:
- 根据渲染树中的信息,浏览器计算出每个节点的确切位置和大小,即所谓的"布局"阶段。
-
绘制:
- 最后一步是将布局后的各个节点转换为屏幕上的实际像素点,也就是我们看到的网页内容。
-
合成:
- 现代浏览器使用多层技术来优化性能,在某些情况下,不同部分可能是分层独立绘制然后合成到一起显示给用户的。
-
更新缓存:
- 在获取新资源后,浏览器会将其存储到本地缓存中,以便下次请求时使用。
关闭TCP连接
四次挥手
在某些情况下,特别是当不再需要保持连接时,客户端和服务器会通过四次挥手来关闭TCP连接。以下是四次挥手的具体步骤:
-
发送FIN报文段:
- 当客户端或服务器决定关闭连接时,它会向对方发送一个FIN(Finish)报文段。
- 这个报文段表示发送方已经没有更多的数据要发送了,但仍然可以接收数据。
-
接收FIN-ACK报文段:
- 对方收到FIN报文段后,会回复一个ACK(Acknowledgment)报文段,确认收到了FIN报文段。
- ACK标志位被设置为1,并且确认号设置为接收到的FIN报文段中的序列号加1。
-
发送FIN报文段:
- 如果对方也有数据需要发送,它会在所有数据发送完毕后,也发送一个FIN报文段给发起关闭的一方。
- 这个FIN报文段同样表示发送方已经没有更多的数据要发送了。
-
接收FIN-ACK报文段:
- 发起关闭的一方收到对方的FIN报文段后,会回复一个ACK报文段,确认收到了FIN报文段。
- 这样,双方都确认了对方没有更多的数据要发送,TCP连接就可以安全地关闭了。
总结
将所有步骤总结为一张图片: