一个页面从输入URL到加载显示完成,这个过程发生了什么?

一、解析URL

1、流程

当在浏览器中输入URL后,浏览器首先对拿到的URL进行识别。判断你输入的是一个合法的 URL 还是一个待搜索的关键词,并且根据你输入的内容进行自动补全、字符编码等操作,解析 URL 得到里面的参数,将域名和需要请求的资源分离开来,从而了解需要请求的是哪个服务器,请求的是服务器上什么资源等等。

URL 就是我们输入的网址,而网址里面含有域名。我们常见的URL是这样的:http://www.baidu.com,这个域名由三部分组成:协议名、域名、端口号,这里端口是默认所以隐藏。

2、URL格式:

image-20240519214908181

protocol://hostname[:port]/path/[;parameters][?query][#fragment]
  • protocol:传输协议
  • hostname:存放资源的服务器的域名或 IP 地址。
  • port:端口号。可选,省略时使用方案的默认端口,HTTP默认为80。
  • path:文件路径。
  • parameters:用于指定特殊参数。可选
  • query:用于给动态网页传递参数。可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开。可选。
  • fragment:信息片段,用于指定网络资源中的片段。可选。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。

3、示例

https://www.baidu.com/s?wd=nginx&tn=25017023_2_dg&ch=8&ie=utf-8
  1. 协议: https:// - 表示这是一个安全的超文本传输协议,用于加密和安全地传输数据。
  2. 域名: www.baidu.com - 这是网站的域名,表示链接指向的是百度的主页。
  3. 查询参数:
    • s: 这是查询参数的键,wdsearch word的缩写,表示搜索词。
    • nginx: 这是查询参数的值,表示用户搜索的关键词是nginx
  4. 追踪代码:
    • tn=25017023_2_dg: 这是追踪代码,通常用于跟踪搜索来源或搜索结果页面的特定参数。tn代表track number,后面的数字和字符是追踪代码的具体值。
  5. 通道代码:
    • ch=8: 这代表搜索结果的通道代码,ch可能代表channel,数字8可能是特定的通道标识。
  6. 字符编码:
    • ie=utf-8: 这表示页面的字符编码是UTF-8,这是一种广泛使用的字符编码,能够支持多种语言的字符。

整个URL的意思是:通过HTTPS协议访问百度的主页,搜索关键词为nginx,并且包含了追踪代码和字符编码的信息。

二、浏览器封装HTTP请求报文

1、流程

URL 进行解析之后,浏览器确定了目标服务器和文件名,接下来就需要根据这些消息封装成一个 HTTP 请求报文发送出去。

2、HTTP请求报文例子

img

3、封装

发送端在层与层之间传输数据时,每经过一层必定会被打上一个该层所属的首部信息。反之,接收端在层与层之间传输数据时,每经过一层就会把该层对应的首部信息消去。

img

三、DNS解析

1、缓存判断

1.1、浏览器缓存

  • 浏览器首先检查自身的DNS缓存。
  • 如果缓存中有对应域名的有效条目(且未超过其TTL(Time To Live)值,即生存时间),则直接使用该IP地址,从而快速开始建立与目标服务器的连接。
  • TTL值由域名所有者在DNS记录中设定,指示了该记录可以被缓存的最大时间长度。
  • 没有则调用系统库函数进行查询。

1.2、操作系统缓存

  • 当浏览器缓存未命中,操作系统(如Windows、macOS、Linux等)会检查其自身的DNS解析缓存。
  • 操作系统也有一个域名解析的过程,在hosts文件里可以读写。
  • 同样,如果找到有效且未过期的记录,系统会直接返回IP地址给浏览器。

1.3、路由器缓存

  • 如果在浏览器和操作系统缓存中都没有找到匹配项,查询请求会到达用户的路由器。
  • 路由器会检查其内置的DNS缓存,看是否之前已经解析过相同域名。
  • 如果路由器缓存中有记录且仍然有效,它会直接将IP地址返回给用户设备,避免进一步向外查询

以上三步都是DNS客户端的缓存

2、递归查询至ISP DNS服务器

  • 若上述缓存均未命中:用户的设备或路由器将DNS请求递归式地发送给ISP(互联网服务提供商)的DNS服务器。
  • ISP DNS 就是在客户端电脑上设置的首选 DNS 服务器,它们在大多数情况下都会有缓存。
  • ISP的DNS服务器尝试在其缓存中查找记录。如果找到,直接返回结果;如果没有,ISP DNS服务器将代表用户继续查询,执行迭代查询直到获得最终IP地址。

3、迭代查询过程

  • 根域名服务器查询:ISP的DNS服务器(或执行递归查询的任何DNS服务器)首先向全球的根域名服务器查询,请求顶级域名(TLD)服务器的地址。
  • 顶级域名服务器查询:根据根域名服务器的回复,查询下一步指向相应的顶级域名服务器(如.com、.org)。
  • 权威DNS服务器查询:顶级域名服务器提供负责具体域名的权威DNS服务器地址,最后查询到达这里,权威DNS服务器直接返回该域名对应的IP地址。

4、保存结果至各级缓存

  • 无论在哪一步骤找到IP地址:该域名-IP映射记录都会在返回路径上的每一个DNS服务器以及最终用户的设备上被缓存。这包括浏览器、操作系统、路由器以及ISP的DNS服务器,确保未来对该域名的查询能够更快地得到响应。

img

DNS 使用的是 UDP 协议,也就是说上面各种请求的转发,都是基于 UDP 这个无连接协议的。

四、建立TCP连接(三次握手)

获取到了目标服务器的 IP 地址之后,此时网络层便会通过IP地址寻得对应服务器的物理地址,这个时候就可以开始发送封装好了的 HTTP 请求报文了

那么既然需要发送请求,必然就需要 TCP 通过三次握手为浏览器和服务器之间建立可靠的连接,保证双方都具有可靠的接收和发送能力。

1、三次握手流程图

img

2、简单理解

  1. 第一次握手(请求建立连接)
    • Alice打电话给Bob:"嗨,Bob,我们今天下午3点在公园门口见面怎么样?"
    • 这相当于客户端发送一个SYN(同步序列编号)包给服务器,表示想要建立连接。
  2. 第二次握手(确认接收)
    • Bob接到了电话,回答Alice:"好的,Alice,下午3点公园门口见,我会准时到的。"
    • 这就像服务器接收到SYN包后,回复一个SYN-ACK(同步-确认)包给客户端,确认收到了连接请求,并告知自己的初始序列号,表示愿意建立连接。
  3. 第三次握手(连接确认)
    • Alice再次回应Bob:"太好了,Bob,我会准时到的,期待见面!"
    • 类比于客户端收到服务器的SYN-ACK后,发送一个ACK(确认)包给服务器,确认客户端已准备好,连接正式建立。

3、具体流程

  • 第一次握手(请求建立连接):

    • 一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态
    • 客户端发送连接请求报文段,将 SYN 标志位设置为 1,表示请求建立连接。seqx。然后,客户端进入 SYN_SENT 状态,等待服务器的确认;
    • 标志位为SYN,表示""请求建立新连接";
      序号为seq=x(x一般为1);
  • 第二次握手(确认接收):

    • 服务器收到客户端发送的 SYN 报文段,需要对这个 SYN 报文段进行确认,设置 ackx+1(seq+1);同时,自己自己还要发送 SYN 请求信息,将 SYN 标志位置为 1,seqy;服务器端将上述所有信息放到一个报文段(即 SYN+ACK 报文段)中,一并发送给客户端,此时服务器进入 SYN_RCVD 状态;
    • 标志位为SYN和ACK,表示"确认客户端的报文seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接"(即告诉客户端,服务器收到了你的数据);
      序号为seq=y;
      确认号为ack=x+1,表示收到客户端的序号seq并将其值加1作为自己确认号ack的值;
  • 第三次握手(连接确认):

    • 客户端收到服务器的 SYN+ACK 报文段。然后将ACK标志位设置为 1,表示确认收到服务器同意连接的信号,向服务器发送 ACK 报文段,这个报文段发送完毕以后,客户端和服务器端都进入 ESTABLISHED 状态,完成 TCP 三次握手。
    • 标志位为ACK,表示"确认收到服务器端同意连接的信号"(即告诉服务器,我知道你收到我发的数据了);
      序号为seq=x+1,表示收到服务器端的确认号ack,并将其值作为自己的序号值;
      确认号为ack=y+1,表示收到服务器端序号seq,并将其值加1作为自己的确认号ack的值;

五、浏览器发送HTTP请求

TCP 三次握手完成后,浏览器与目标服务器之间就建立了一个可靠的虚拟通道,于是浏览器就可以发送自己的 HTTP 请求了。

请求报文的结构

img

1. 应用层 (HTTP)

  • HTTP协议:浏览器构造HTTP请求报文,这是在应用层完成的。HTTP定义了客户端和服务器之间的通信格式,包括请求方法、URL、头部字段和可选的请求体。

2. 传输层 (TCP)

  • TCP协议:应用层生成的HTTP报文被传输层的TCP协议封装,通过TCP段的形式发送。TCP负责将数据分割成适当大小的段,为每个段添加源端口和目的端口信息,以及序列号和确认号等,以确保数据的可靠传输、错误检测、流量控制和拥塞控制。

3. 网络层 (IP)

  • IP协议:TCP段再被封装到IP数据包中。IP层负责将数据包从源主机路由到目标主机,通过分配给每个数据包一个源IP地址和目的IP地址,实现跨网络的寻址和传输。

4. 数据链路层 (以太网、Wi-Fi等)

  • 以太网帧或Wi-Fi帧:在局域网中,IP数据包被进一步封装成适合物理媒介传输的数据帧,例如以太网帧。数据链路层通过MAC地址标识网络中的设备,并提供错误检测功能(如CRC校验)。

img

六、服务器处理请求

1、流程

preview

2、处理请求

接受 TCP 报文后,会对连接进行处理,对HTTP协议进行解析(请求方法、域名、路径等),并且进行一些验证:

  • 验证是否配置虚拟主机
  • 验证虚拟主机是否接受此方法
  • 验证该用户可以使用该方法(根据 IP 地址、身份信息等)

七、返回HTTP响应

1、响应报文的结构

img

2、状态码

类别 描述
1xx 信息性状态码 接受的请求正在处理
2xx 成功状态码 请求正常处理完毕
3xx 重定向状态码 需要进行附加操作以完成请求
4xx 客户端错误状态码 服务器无法处理请求
5xx 服务器错误状态码 服务器处理请求出错

3、常见的状态码

状态码 含义
100 请求已经接收,客户端可以继续发送请求
101 服务器已经收到并且理解了客户端的请求
200 一切正常
204 请求成功,无资源可返回
206 范围请求,请求范围内资源正常返回
301 永久重定向
302 暂时重定向,URL可能还会改变
400 请求存在语法错误
401 请求需要有通过HTTP认证的认证信息
403 禁止访问
404 资源没找到,not found
500 服务端处理请求发生了错误,或web应用存在某些bug或临时的故障
503 服务器过载或者临时维护
504 网关超时,代理服务器等待应用服务器响应时的超时

八、浏览器接受响应

服务器在接收到浏览器发送的HTTP请求之后,会将收到的HTTP报文封装成HTTP的Request对象,并通过不同的web服务器进行处理,处理完的结果以HTTP的Response对象返回,主要包含状态码,响应头,响应报文三个部分。

1、流程

  • 首先查看 Response header,根据不同状态码做不同的事(比如上面提到的重定向)。

  • 如果响应资源进行了压缩(比如 gzip),还需要进行解压。

  • 然后,对响应资源做缓存。

  • 接下来,根据响应资源里的 MIME 类型去解析响应内容(比如 HTML、Image各有不同的解析方式)。

九、浏览器进行语法解析,渲染页面

1、流程图

redning_process


rendingtree

3、具体流程

下载完的网页将被交给浏览器内核(渲染进程)进行处理:

  1. 根据顶部定义的DTD类型进行对应的解析方式;
  2. 渲染进程内部是多线程的,网页的解析将会被交给内部的GUI渲染线程处理;
  3. 首先渲染线程中的HTML解释器,将HTML网页和资源从字节流解释转换成字符流;
  4. 再通过词法分析器将字符流解释成词语;
  5. 之后经过语法分析器根据词语构建成节点;最后通过这些节点组建一个DOM树;
  6. 这个过程中,如果遇到的DOM节点是JavaScript代码,就会调用JavaScript引擎对JavaScript代码进行解释执行,此时由JavaScript引擎和GUI渲染线程的互斥,GUI渲染线程就会被挂起,渲染过程停止;如果JavaScript代码的运行中对DOM树进行了修改,那么DOM的构建需要从新开始;
  7. 如果节点需要依赖其他资源,如(图片,CSS等),便会调用网络模块的资源加载器来加载它们,但它们是异步的,不会阻塞当前DOM树的构建;
  8. 如果遇到的是JavaScript资源URL(没有标记异步),则需要停止当前DOM的构建,直到JavaScript的资源加载并被JavaScript引擎执行后才继续构建DOM;
  9. 对于CSS,CSS解释器会将CSS文件解释成内部表示结构,生成CSS规则树;
  10. 然后合并CSS规则树和DOM树,生成render渲染树;
  11. 最后对render树进行布局和绘制,并将结果通过IO线程传递给Browser控制进程进行显示。

十、关闭TCP连接(四次挥手)

完成一次 HTTP 请求后,服务器并不是马上断开与客户端的连接。在 HTTP/1.1 中,Connection: keep-alive 是默认启用的,表示持久连接,以便处理不久后到来的新请求,无需重新建立连接而增加慢启动开销,提高网络的吞吐能力。

为了避免服务器与客户端双方的资源占用和损耗,当双方没有请求或响应传递时,任意一方都可以发起关闭请求。与创建TCP连接的3次握手类似,关闭TCP连接,需要4次握手。

1、四次挥手流程图

7d3aa066c42843d9b03f0be303cd172c

2、简单理解

  1. 第一次挥手(FIN请求断开)
    • Alice对Bob说:"Bob,我们聊得差不多了,我这边准备挂电话了。"
    • 这对应于TCP连接中的一方(假设是客户端)发送一个FIN标志位的包给另一方(服务器),表示自己没有更多数据要发送了,希望关闭连接。
  2. 第二次挥手(ACK确认收到)
    • Bob回应Alice:"好的,Alice,我知道了,你随时可以挂。"
    • 服务器接收到客户端的FIN包后,回复一个ACK包,确认收到了断开连接的请求,但此时服务器可能还有数据要发送,所以连接并未立即关闭。
  3. 第三次挥手(服务器FIN请求断开)
    • 过了一会儿,Bob说:"Alice,我也讲完了,现在我们真的可以结束了。"
    • 一旦服务器准备好关闭连接,它也会发送一个带有FIN标志位的包给客户端,表示它也不再发送数据了。
  4. 第四次挥手(客户端ACK确认)
    • Alice回答:"好的,Bob,再见!祝你有美好的一天。"
    • 客户端收到服务器的FIN包后,发送最后一个ACK包,确认收到了服务器的断开请求。此时,两边都知道连接可以安全关闭了。

3、具体流程

  • 第一次挥手:

    • 客户端想要释放连接,向服务器发送FIN报文,将FIN标记位设置为1,同时指定一个序列号seq=u。随后客户端进入FIN_WAIT_1状态。

    • 标志位为FIN,表示"请求释放连接";

      序号为seq=u;

  • 第二次挥手:

    • 服务器端接收到从客户端发出的FIN报文后,确认了客户端想要释放连接,随后服务器端

      会发送ACK报文,并且把客户端的序列号+1作为ACK报文的序列号值。表明已经收到客户端的报文,此时服务器端处于CLOSE_WAIT状态。

    • 随后服务器端开始准备释放服务器端到客户端方向上的连接。客户端收到从服务器端发出的ACK应答报文,确认了服务器收到了客户端发出的释放连接请求。随后客户端结束FIN_WAIT_1状态进入FIN_WAIT_2状态。

    • 标志位为ACK,表示"接收到客户端发送的释放连接请求";

      序号为seq=v;

      确认号为ack=u+1;表示是在接收到客户端报文的基础上,将其序号seq值加1作为本段报文确认号ack的值

  • 第三次挥手:

    • 服务器端自从发出ACK确认报文之后,经过CLOSE_WAIT阶段,服务器端将最后数据发送完毕后就向客户端发出连接释放报文段,报文包含FINACK标志位。随后服务器端结束CLOSE_WAIT状态,进入LAST_ACK状态。并且停止再服务器端到客户端方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。

    • 标记位为FIN和ACK,表示"已经准备好释放连接了"。

      序号为seq=w;

      确认号为ack=u+1;

  • 第四次挥手:

    • 客户端收到来自服务器端发出的FIN+ACK报文,确认了服务器端已做好释放连接的准备,结束FIN_WAIT_2状态,并向服务器端发送一个ACK报文作为应答,将服务器端的序列号值+1作为自己的ACK报文的序列号值。进入TIME_WAIT状态。

    • 服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。

    • 客户端等待计时器设置的时间2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,至此完成"四次挥手"。

    • 标记位为ACK,表示"接收到服务器准备好释放连接的信号"。

      序号为seq=u+1;表示是在收到了服务器端报文的基础上,将其确认号ack值作为本段报文序号的值。

      确认号为ack=w+1;表示是在收到了服务器端报文的基础上,将其序号seq值作为本段报文确认号的值。

posted @ 2024-05-19 23:44  misakivv  阅读(133)  评论(0编辑  收藏  举报