高频经典面试题——从输入网址到网页显示,这期间发生了什么?

71 阅读10分钟

前言

话不多说,直接进入正题。

步骤

总体分为以下几个步骤:

  1. 在浏览器输入指定网址,浏览器解析URL
  2. 浏览器通过DNS进行域名解析,获取IP地址
  3. 浏览器通过IP和端口号,向目标服务器发起TCP连接请求
  4. 浏览器在TCP连接上,向服务器发送一个请求报文,请求获取网页的内容
  5. 服务器处理收到的请求,返回响应报文至浏览器
  6. 浏览器收到HTTP响应
  7. 读取页面内容,浏览器渲染,解析html源码
  8. 断开TCP连接

1. 浏览器解析URL

首先浏览器需要先对 URL 进行解析,对 URL 进⾏解析之后,浏览器确定了 Web 服务器和⽂件名,然后根据这些信息来⽣成 HTTP 请求消息。

URL是什么?

URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上资源,俗称网址。 比如[www.baidu.com/s?cl=3] 遵守以下的语法规则:

  1. scheme:指定访问资源所使用的协议类型(常见的协议有 http、https、ftp、file,其中最常见的类型是 http,而 https 则是进行加密的网络传输)
  2. host:表示提供资源的主机名或服务器地址(如www.example.com)
  3. domain:主机名中的域名部分,用于标识网络中的组织或站点(如example.com)
  4. port:服务器上用于区分具体服务的端口号(http的默认端口号是80)
  5. path:服务器中资源所在的目录路径,用来定位资源位置(如/archive/)
  6. filename:路径中具体资源(通常是文件)的名称(如report.pdf)
  7. paramter: 携带的参数由?后的内容组成(图中没有绘出,但可自行查看网页上的URL)
显示有误

所以URL实际上用来请求服务器的文件资源,那么就有个疑问:如果省略定位资源的部分,那应该是请求的什么文件?

当没有路径名时,就代表访问根⽬录下事先设置的默认⽂件,也就是 /index.html 或者 /default.html 这些⽂件,这样就不会发⽣混乱了。

2. 域名解析(DNS)

通过浏览器解析 URL 并⽣成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器。但在发送之前,还有⼀项⼯作需要完成,那就是查询服务器域名对应的 IP 地址,因为委托操作系统发送消息时,必须提供通信对象的 IP 地址。

所以,有⼀种服务器就专门保存了 Web 服务器域名与 IP 的对应关系,它就是 DNS 服务器。

域名层级关系

www.baidu.com :DNS的域名使用"."来分隔,越靠右的位置代表着域名的层级越高,实际上域名最后还有一个".",最后一个点代表根域名:[www.baidu.com.]

域名层级类似一个树状结构:

  • 根DNS服务器(.)
  • 顶级域DNS服务器(.com)
  • 权威DNS服务器(baidu.com)
显示有误

域名解析的工作流程

  1. 客户端发起 DNS 查询,请求解析域名 [www.baidu.com] 对应的 IP 地址,并将该请求发送至本地 DNS 服务器(即在客户端 TCP/IP 设置中填写的 DNS 服务器)。
  2. 本地 DNS 服务器接收到请求后,首先在本地缓存中进行查询。若缓存中已存在 [www.server.com] 的解析记录,则直接将对应的 IP 地址返回给客户端;若未命中缓存,则向根域名服务器发起查询请求。
  3. 根域名服务器收到来自本地 DNS 服务器的查询请求后,根据域名后缀识别出该域名属于 .com 顶级域名,并返回负责 .com 顶级域的顶级域名服务器(TLD Server)的地址。根域名服务器本身不提供具体的域名解析结果,仅用于指引查询路径。
  4. 本地 DNS 服务器根据根域名服务器返回的信息,向 .com 顶级域名服务器发起查询,请求获取 [www.server.com] 的解析信息。
  5. 顶级域名服务器接收到请求后,返回负责 server.com 域的权威 DNS 服务器的地址,而不直接提供最终的 IP 地址。
  6. 本地 DNS 服务器随后向 server.com 的权威 DNS 服务器发起查询请求。权威 DNS 服务器是该域名解析数据的最终来源,负责维护并提供域名与 IP 地址之间的映射关系。
  7. 权威 DNS 服务器查询其解析记录后,将 www.server.com 对应的 IP 地址返回给本地 DNS 服务器。
  8. 本地 DNS 服务器将最终获得的 IP 地址返回给客户端,客户端据此与目标服务器建立网络连接。

3. 浏览器通过IP和端口号,向目标服务器发起TCP连接请求

协议栈

显示有误

应用程序浏览器获得IP和端口号后,通过调用 Socket 库来委托操作系统内核中的 TCP/IP 协议栈 工作。

协议栈的上层由传输层协议组成,主要包括分别负责收发数据的 TCPUDP 协议。

协议栈的下层是 IP 协议控制网络包收发操作,它的作用是将数据拆分成一个个网络包,并将这些网络包发送到网络中的目标主机。

其中 IP 还包括 ICMP 协议和 ARP 协议,ICMP协议用于传递网络错误和控制信息,配合 ARP 协议根据 IP 地址查找对应得网卡 MAC 地址

再往下层的网卡驱动程序负责控制具体的网卡设备,而网卡则负责将数据转换为网络信号,在网络中实际发送和接收数据。

HTTP1.0/HTTP2.0/HTTPs等是基于TCP协议传输的,DNS/视频流/实时通信是基于UDP进行传输

TCP建立连接:三次握手

显示有误
在HTTP传输数据之前,首先需要TCP建立连接,TCP连接的建立,通常称为“三次握手”。

一开始,客户端和服务器都处于 CLOSED 状态,先是服务器主动监听某个端口,处于 LISTEN 状态。

  • 第一次握手(SYN)
    客户端向服务端发送一个 SYN 报文段,用于请求建立连接。该报文段中包含客户端生成的初始序列号(ISN),记为 seq = x。发送完成后,客户端进入 SYN_SENT 状态,等待服务端响应。

  • 第二次握手(SYN + ACK)
    服务端收到客户端的 SYN 报文段后,若同意建立连接,则向客户端返回一个 SYN+ACK 报文段。其中,seq = y 表示服务端生成的初始序列号,ack = x + 1 用于确认已收到客户端的 SYN 请求。此时,服务端进入 SYN_RCVD(SYN_RECV) 状态。

  • 第三次握手(ACK)
    客户端收到服务端的 SYN+ACK 报文段后,向服务端发送一个 ACK 报文段进行确认,其确认号为 ack = y + 1。客户端发送该报文段后进入 ESTABLISHED 状态;服务端在收到该 ACK 报文段后,也进入 ESTABLISHED 状态,TCP 连接正式建立。

为什么要三次握手? 三次握手是为了保证双方都有发送和接受的能力,其核心目的是为了在客户端和服务器之间建立一个可靠的、全双工的通信信道,这需要实现两个主要目标:

  1. 确认双方的收发能力,并同步初始序列号 (ISN)
  2. 防止已失效的连接请求被错误地建立

4. 浏览器在TCP连接上,向服务器发送一个请求报文,请求获取网页的内容

TCP 三次握手结束后,开始发送 HTTP 请求报文。

请求报文由请求行(request line)、请求头(header)、请求体三个部分组成,如下图所示:

显示有误

请求行

请求行包含请求方法、URL、协议版本,在请求报文中只占一行

  • 请求方法包含 8 种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE
  • URL 即请求地址,HTTP/1.1中请求行通常不是完整的URL,主机和端口一般放在Host请求头中
  • 协议版本即HTTP版本号 GET /index.html?user=tom HTTP/1.1

请求头

请求头包含请求的附加信息,由关键字/值对组成,每行一对,关键字和值用冒号":"分隔

请求体

请求体可以承载多个请求参数的数据,包含回车符、换行符和请求数据,并不是所有请求都具有请求数据

5. 服务器处理收到的请求,返回响应报文至浏览器

HTTP响应报文一般由三大部分组成:状态行、消息头、消息体

显示有误

状态行

状态行在响应报文的第一行,用来说明服务器对请求的处理结果,格式是HTTP版本 状态码 原因短语 例如:HTTP/1.1 200 OK

消息头

状态行下面是若干行消息头,每一行都是 头字段名: 值 的形式,用来描述响应数据的属性,比如数据类型、长度、缓存方式等。常见的有 Content-Type(告诉浏览器返回的是什么类型数据)、Content-Length(消息体长度)、Set-Cookie 等。所有消息头结束后必须有一个空行,用来标志“头部结束、正文开始”。

消息体

空行之后的内容就是消息体,也就是服务器真正返回给浏览器的数据。它可以是 HTML 页面、JSON 数据、图片的二进制内容等,具体如何解析完全由 Content-Type 决定。有些响应(如 204 No Content)可能没有消息体。

6. 浏览器收到HTTP响应

7. 读取页面内容,浏览器渲染,解析html源码

8. 断开TCP连接

浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。

四次挥手

TCP 连接的断开需要经过四次报文交换,以确保通信双方的数据都能被正确发送和接收。

显示有误
  • 第一次挥手(FIN)
    当客户端(或通信任意一方)决定关闭连接时,会向对方发送一个带有 FIN 标志位的报文段,表示自身已无数据需要继续发送。该报文段包含序列号 seq = u。发送完成后,主动关闭连接的一方进入 FIN-WAIT-1 状态。

  • 第二次挥手(ACK)
    对方收到 FIN 报文段后,立即发送一个 ACK 确认报文段进行响应,其确认号为 ack = u + 1,表示已成功接收到关闭请求。此时,对方进入 CLOSE-WAIT 状态,而主动关闭连接的一方在收到该 ACK 后进入 FIN-WAIT-2 状态。此阶段连接处于半关闭状态,即主动关闭方不再发送数据,但被动关闭方仍可继续发送未完成的数据。

  • 第三次挥手(FIN)
    当被动关闭方确认自身的数据已全部发送完成后,会向对方发送一个 FIN 报文段,表示其也准备关闭连接。该报文段包含序列号 seq = y。发送后,被动关闭方进入 LAST-ACK 状态,等待最终确认。

  • 第四次挥手(ACK)
    主动关闭方收到该 FIN 报文段后,向对方发送一个最终的 ACK 确认报文段,其确认号为 ack = y + 1。随后,主动关闭方进入 TIME-WAIT 状态;被动关闭方在收到该 ACK 后立即进入 CLOSED 状态,连接正式关闭。主动关闭方需在 TIME-WAIT 状态下等待 2MSL(最大报文段生存时间) ,以确保对方能够收到最终的确认报文,之后才进入 CLOSED 状态。