Skip to content
目录

基础知识

HTTP 请求

从浏览器地址栏输入 url 到请求返回发生了什么

当你在浏览器地址栏输入 URL 并按下回车后,会发生一系列复杂的过程。以下是这个过程的简化版:

  1. DNS 解析:浏览器首先需要知道服务器的 IP 地址。它通过 DNS(域名系统) 解析来完成这个任务。浏览器首先检查本地缓存是否有该域名对应的 IP 地址,如果没有,它会向 DNS 服务器发送一个请求,DNS 服务器会返回对应的 IP 地址。
  2. 建立 TCP 连接:一旦浏览器获得了服务器的 IP 地址,它会尝试建立一个 TCP 连接。这通常通过三次握手完成:首先,客户端发送一个 SYN 包;然后,服务器回应一个 SYN-ACK 包;最后,客户端发送一个 ACK 包。
  3. 发送 HTTP 请求:TCP 连接建立后,浏览器就可以向服务器发送 HTTP 请求了。这个请求包含了很多信息,比如请求的方法 (GET、POST 等)、请求的资源 (URL)、请求头 (包含了如 User-Agent、Cookie 等信息) 等。
  4. 服务器处理请求并返回 HTTP 响应:服务器接收到 HTTP 请求后,会根据请求信息处理请求,然后返回一个 HTTP 响应。响应包含了状态码 (如 200 表示成功,404 表示资源未找到),响应头 (如 Content-Type、Set-Cookie 等) 和响应体 (通常是请求的资源)。
  5. 浏览器处理响应:浏览器接收到 HTTP 响应后,会根据响应头的 Content-Type 来处理响应体。如果是一个 HTML 文档,浏览器会解析 HTML,并请求其中的其他资源 (如 CSS、JavaScript、图片等)。然后,浏览器会根据 HTML、CSS 和 JavaScript 渲染页面。
  6. 关闭 TCP 连接:最后,浏览器和服务器会关闭 TCP 连接。这通常通过四次挥手完成:首先,客户端发送一个 FIN 包;然后,服务器回应一个 ACK 包;接着,服务器发送一个 FIN 包;最后,客户端回应一个 ACK 包。

以上就是从浏览器地址栏输入 URL 到请求返回发生的过程。实际上,这个过程可能会更复杂,因为还可能涉及到缓存、代理、CDN、HTTPS 等多种技术。

说说建立 TCP 连接的三次握手,为什么两次不行?

TCP 连接的建立过程通常被称为"三次握手",具体步骤如下:

  1. 第一次握手:客户端发送一个 SYN 包 (同步序列编号) 到服务器,请求建立连接。这个包中包含了客户端的初始序列号。这一步完成后,客户端进入 SYN_SENT 状态。
  2. 第二次握手:服务器收到 SYN 包后,如果同意建立连接,会发送一个 SYN+ACK 包给客户端。这个包中包含了服务器的初始序列号和对客户端初始序列号的确认。这一步完成后,服务器进入 SYN_RCVD 状态。
  3. 第三次握手:客户端收到 SYN+ACK 包后,会发送一个 ACK 包给服务器,确认服务器的初始序列号。这一步完成后,客户端和服务器都进入 ESTABLISHED 状态,TCP 连接建立成功。

那么,为什么需要三次握手,两次不行呢?

这是因为 TCP 是一种可靠的连接,需要保证数据的完整性和准确性。三次握手可以确保双方都有能力发送和接收数据。如果只进行两次握手,那么一方可能无法确认对方已经准备好接收数据,这样就可能导致数据的丢失。

例如,如果只进行一次握手 (客户端发送 SYN 包给服务器),那么客户端就会认为连接已经建立,开始发送数据。但是,如果服务器并没有准备好接收数据,那么这些数据就会丢失。

同样,如果只进行两次握手 (客户端发送 SYN 包给服务器,服务器回复 SYN+ACK 包),那么虽然客户端知道服务器已经准备好接收数据,但是服务器并不知道客户端是否已经准备好发送数据。如果此时服务器开始发送数据,而客户端并没有准备好接收,那么这些数据也会丢失。

因此,为了确保双方都已经准备好发送和接收数据,需要进行三次握手。

说说关闭 TCP 连接的四次分手,为什么三次不行?

TCP(传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议。在 TCP 连接的生命周期中,建立连接和关闭连接都需要经过一个四步过程,这也被称为 TCP 的四次握手 (建立连接) 和四次挥手 (关闭连接)。

关闭 TCP 连接的四次挥手过程如下:

  1. 第一次挥手:主动关闭方 (假设为 A) 发送一个 FIN 标志的数据包给被动关闭方 (假设为 B),表示 A 已经没有数据要发送了。
  2. 第二次挥手:B 收到 A 的 FIN 包后,发送一个 ACK 包给 A,表示已经收到了 A 的关闭请求。
  3. 第三次挥手:当 B 发送完所有数据后,也会发送一个 FIN 包给 A,表示 B 也已经没有数据要发送了。
  4. 第四次挥手:A 收到 B 的 FIN 包后,发送一个 ACK 包给 B,表示已经收到了 B 的关闭请求。至此,TCP 连接关闭。

那么,为什么需要四次挥手,而不是三次或者更少呢?这是因为 TCP 是全双工的协议,发送和接收是可以同时进行的。当一方主动关闭连接时,只是表示它已经没有数据要发送了,但并不意味着它不再接收数据。所以,即使 A 发送了 FIN 包,B 也需要确认并且回复一个 FIN 包,表示它也没有数据要发送了。这样,双方都确认了对方没有数据要发送,连接才能完全关闭。这就是为什么需要四次挥手的原因。

说说 dns 解析流程

DNS(Domain Name System) 解析流程是将域名转换为 IP 地址的过程。以下是详细的步骤:

  1. 浏览器缓存:当你输入一个 URL 并按下回车后,浏览器会首先查看自己的缓存中是否有这个域名对应的 IP 地址,如果有,直接返回,结束解析。
  2. 系统缓存:如果浏览器缓存中没有,系统会查看本地 Host 文件是否有这个域名的映射关系,如果有,直接返回,结束解析。
  3. 路由器缓存:如果系统缓存中也没有,会查看路由器缓存。
  4. ISP DNS 缓存:如果前面都没有找到,操作系统会将域名发送到 ISP 的 DNS 服务器,在这里进行解析。
  5. 根域名服务器:如果 ISP 的 DNS 服务器中也没有对应的映射关系,它会将请求发送到根域名服务器。根域名服务器是最高级别的 DNS 服务器,它知道所有顶级域名服务器的 IP 地址。
  6. 顶级域名服务器:根域名服务器会返回一个负责该顶级域名 (如。com, .org 等) 的顶级域名服务器的 IP 地址。ISP 的 DNS 服务器再向这个顶级域名服务器发出请求。
  7. 权威 DNS 服务器:顶级域名服务器会返回负责该域名的权威 DNS 服务器的 IP 地址。ISP 的 DNS 服务器再向这个权威 DNS 服务器发出请求,这个服务器就能返回对应的 IP 地址。
  8. 缓存 IP 地址:ISP 的 DNS 服务器将解析的结果返回给操作系统,同时将这个结果缓存起来,以备后续查询使用。操作系统再将结果返回给浏览器,浏览器将 IP 地址缓存起来,然后通过 IP 地址建立连接。

以上就是 DNS 解析的整个过程,它可能涉及到多个服务器,跨越多个网络节点,但是由于 DNS 的高度缓存机制,实际上在大多数情况下,这个过程的延迟都控制在了毫秒级别。

html 如何做 dns 优化

DNS 优化是一种提高网站加载速度的方法,主要通过减少 DNS 解析时间来实现。以下是一些在 HTML 中进行 DNS 优化的方法:

  1. DNS 预解析 (DNS Prefetching):DNS 预解析是一种让浏览器主动去解析域名的方法,可以减少用户在点击链接时的等待时间。在 HTML 中,可以通过在<head>标签内添加<link rel="dns-prefetch" href="//example.com">来实现。
  2. 使用 CDN:内容分发网络 (CDN) 可以将网站的内容分发到全球的各个节点,用户可以从最近的节点获取内容,从而减少 DNS 解析时间。
  3. 减少域名数量:每个新的域名都需要进行 DNS 解析,因此减少域名的数量可以减少 DNS 解析时间。例如,可以将所有的资源都放在同一个域名下,或者使用数据 URI 来代替小图片。
  4. 使用持久连接:持久连接可以让浏览器在一个连接上发送和接收多个请求,从而减少了 DNS 解析的次数。
  5. 使用 HTTP/2:HTTP/2 支持多路复用,可以在一个连接上并行发送和接收多个请求,从而减少了 DNS 解析的次数。
  6. 缓存 DNS 解析结果:浏览器会缓存 DNS 解析的结果,但是这个缓存的时间通常很短。可以通过设置 DNS 记录的 TTL(生存时间) 来增加缓存的时间。

以上就是在 HTML 中进行 DNS 优化的一些方法,通过这些方法可以有效地提高网站的加载速度。

encodeURIComponent 与 encodeURI 有什么区别?

encodeURIComponentencodeURI都是 JavaScript 中用于编码 URI 的内置函数,但它们的使用场景和编码方式有所不同。

  1. encodeURI:这个函数用于编码整个 URI。它不会对某些具有特殊含义的字符进行编码,如冒号、正斜杠、问号和井号等。这是因为这些字符在 URI 中有特殊的含义,如果被编码,可能会改变 URI 的解析结果。例如:
javascript
console.log(encodeURI('https://www.example.com/path?name=test#top'));
// 输出:https://www.example.com/path?name=test#top
  1. encodeURIComponent:这个函数用于编码 URI 的组成部分,它会对几乎所有的字符进行编码。在编码查询字符串或者路径参数时,通常会使用这个函数。例如:
javascript
console.log(encodeURIComponent('https://www.example.com/path?name=test#top'));
// 输出:https%3A%2F%2Fwww.example.com%2Fpath%3Fname%3Dtest%23top

总的来说,当你需要编码整个 URI 时,应该使用encodeURI;当你需要编码 URI 的某个部分 (如查询字符串或路径参数) 时,应该使用encodeURIComponent

从网卡把数据包传输出去到服务器发生了什么?

当从网卡发送数据包到服务器时,会经历以下步骤:

  1. 数据包生成:首先,应用程序生成数据,然后由操作系统将这些数据打包成一个或多个数据包。每个数据包都包含源和目标 IP 地址,以及其他控制信息。
  2. 数据包发送:然后,数据包被发送到网络适配器 (网卡),网卡将数据包转换为电信号 (有线网络) 或无线信号 (无线网络),然后通过网络传输。
  3. 路由:数据包在网络中传输时,需要通过多个路由器和交换机。每个路由器都会查看数据包的目标 IP 地址,然后决定将数据包发送到哪个方向。这个过程称为路由。
  4. 到达服务器:最后,数据包到达目标服务器的网络适配器,然后被转换回数字数据,并传递给操作系统。操作系统将数据包解包,然后将数据发送给目标应用程序。
  5. 确认收到:服务器收到数据包后,通常会发送一个确认信号回源设备,告知数据包已经成功接收。

这个过程可能会受到许多因素的影响,包括网络拥塞、硬件故障、软件错误等。因此,网络通信通常需要一些错误检测和恢复机制,以确保数据的正确传输。

说说浏览器缓存,有哪几种类型?

浏览器缓存是一种在本地存储用户下载的各种网页资源的技术,包括 HTML 文件、CSS 样式表、JavaScript 脚本、图片、视频等。当用户再次访问同一页面时,浏览器可以直接从本地缓存中读取资源,而不必再次向服务器发送请求,从而提高页面加载速度,减少数据传输,节省带宽。

浏览器缓存主要分为两种类型:强缓存和协商缓存。

  1. 强缓存:通过设置 HTTP 响应头中的 Expires 或 Cache-Control 字段来实现。当浏览器再次请求该资源时,会先检查本地缓存是否存在该资源并且是否在有效期内,如果是,则直接从缓存中读取,不会向服务器发送请求。
  2. 协商缓存:当强缓存失效后,浏览器会向服务器发送请求,检查资源是否有更新。服务器会通过请求头中的 If-Modified-Since 或 If-None-Match 字段来判断资源是否有更新。如果没有更新,服务器会返回 304 状态码,浏览器会继续从缓存中读取资源;如果有更新,服务器会返回新的资源和 200 状态码,浏览器会更新缓存并加载新的资源。

最后更新时间: