从输入URL到整个页面显示在用户面前发生了什么

大体流程

  1. 浏览器从url中解析出服务器的主机名
  2. 浏览器将服务器的主机名转换成服务器的IP地址(DNS)
  3. 浏览器将端口号从url中解析出来
  4. 浏览器建立一条与web服务器的TCP连接
  5. 浏览器向服务器发送一条HTTP的请求报文
  6. 服务器向浏览器回送一条HTTP的响应报文
  7. 关闭连接,浏览器渲染

1. 浏览器查找域名对应的IP地址

IP地址:IP协议为互联网上的每一个网络和每一台主机都分配的一个逻辑地址。通过IP地址才能确定一台主机(服务器)的位置。

域名(DN,Domain Name):IP地址不便于用户记忆和使用,故用域名来代替纯数字的IP地址。

DNS(Domain Name System):每个域名都对应一个或多个提供相同服务的服务器的IP地址,只有知道服务器IP地址才能建立连接,所以需要通过DNS把域名解析成一个IP地址。

域名和IP的关系

域名和IP不是一一对应的关系,可以把多个提供相同服务的服务器IP设置为同一个域名,同一时刻一个域名可以解析出多个IP地址;同时,一个IP地址可以绑定多个域名,数量不限。

再强调一下,同一时刻一个域名是可以解析出多个IP地址的(多条A记录很常见)。只是每次域名解析请求会根据对应的负载均衡算法计算出一个IP地址返回给访客。

bash
vivi@vivi:~$ nslookup aliyun.com
Server:		127.0.0.53
Address:	127.0.0.53#53

Non-authoritative answer:
Name:	aliyun.com
Address: 140.205.60.46
Name:	aliyun.com
Address: 106.11.172.9
Name:	aliyun.com
Address: 140.205.135.3
Name:	aliyun.com
Address: 106.11.253.83
Name:	aliyun.com
Address: 106.11.249.99
Name:	aliyun.com
Address: 106.11.248.146
Name:	aliyun.com
Address: 2401:b180:1:60::6
Name:	aliyun.com
Address: 2401:b180:1:60::5

vivi@vivi:~$ dig aliyun.com

; <<>> DiG 9.16.1-Ubuntu <<>> aliyun.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47126
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;aliyun.com.			IN	A

;; ANSWER SECTION:
aliyun.com.		300	IN	A	106.11.248.146
aliyun.com.		300	IN	A	106.11.249.99
aliyun.com.		300	IN	A	106.11.253.83
aliyun.com.		300	IN	A	140.205.135.3
aliyun.com.		300	IN	A	106.11.172.9
aliyun.com.		300	IN	A	140.205.60.46

;; Query time: 8 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN:  2 21 16:12:48 CST 2024
;; MSG SIZE  rcvd: 135
vivi@vivi:~$ nslookup aliyun.com
Server:		127.0.0.53
Address:	127.0.0.53#53

Non-authoritative answer:
Name:	aliyun.com
Address: 140.205.60.46
Name:	aliyun.com
Address: 106.11.172.9
Name:	aliyun.com
Address: 140.205.135.3
Name:	aliyun.com
Address: 106.11.253.83
Name:	aliyun.com
Address: 106.11.249.99
Name:	aliyun.com
Address: 106.11.248.146
Name:	aliyun.com
Address: 2401:b180:1:60::6
Name:	aliyun.com
Address: 2401:b180:1:60::5

vivi@vivi:~$ dig aliyun.com

; <<>> DiG 9.16.1-Ubuntu <<>> aliyun.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47126
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;aliyun.com.			IN	A

;; ANSWER SECTION:
aliyun.com.		300	IN	A	106.11.248.146
aliyun.com.		300	IN	A	106.11.249.99
aliyun.com.		300	IN	A	106.11.253.83
aliyun.com.		300	IN	A	140.205.135.3
aliyun.com.		300	IN	A	106.11.172.9
aliyun.com.		300	IN	A	140.205.60.46

;; Query time: 8 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN:  2 21 16:12:48 CST 2024
;; MSG SIZE  rcvd: 135

DNS重定向

这里的知识点,对前端而言只要知道使用CDN存放静态资源这种优化策略的原理是DNS负载均衡: 如果一个大型网站的所有请求都由同一个服务器进行处理,是不现实的; 并且对用户而言,用户并不关注具体是哪台机器处理了他的请求。 因此,DNS可以根据多个服务器中每个服务器的负载量、该机器离用户的地理位置的距离等信息 返回其中某个适合的主机的IP地址,这个过程就是DNS负载均衡,又叫做DNS重定向CDN(Content Delivery Network)就是利用DNS的重定向技术,DNS服务器会返回一个跟用户最接近的点的IP地址。

要实现一个域名对应多个IP地址的效果,首先需要了解DNS(域名系统)的工作原理。

DNS(Domain Name System)是因特网的一项服务,它作为域名和IP地址相互映射的一个分布式数据库,能够使人们更方便地访问互联网。我们平时访问网站更多的是通过域名而非IP地址去触达,但域名并不能被计算机直接识别,所以需要通过DNS将域名“翻译”成可由计算机直接识别的IP地址。具体的操作方式,是在DNS解析操作平台,添加一条解析记录(A记录或AAAA记录),将网站的域名指向服务器的IP地址。一般情况下,一个域名对应一个IP地址,也就只需添加一条解析记录即可。如果想要实现一个域名对应多个IP地址,就需要添加多条解析记录,这也是通过DNS实现负载均衡的简单原理。

如我们想要将http://www.example.com这个域名分别指向1.1.1.1(北京电信)、2.2.2.2(上海移动)、3.3.3.3(深圳联通)三个IP。那么我们就可以在DNS服务器中配置三个A记录,分别为

这样,每次域名解析请求都会根据对应的负载均衡算法计算出一个不同的IP地址返回给访客,这样就构成了一个服务器集群,并实现负载均衡的效果。在实际场景中,当北京用户访问http://www.example.com域名时,DNS会根据负载均衡算法和A记录得出一个就近IP地址1.1.1.1返回给客户端,当上海用户访问http://www.example.com域名时,DNS就会返回给2.2.2.2的服务器地址,深圳用户返回3.3.3.3。

不同用户就近访问不同的服务器IP地址,访问速度大大提升,同时也减轻了单个服务器的访问压力。

实现负载均衡的方式有很多种,其中DNS是一种十分简单和有效的技术手段,它主要有以下几点优势:

  • 将负载均衡工作交给DNS,省去了网站管理维护负载均衡服务器的麻烦;
  • 技术实现比较灵活,操作简单,成本低,适用于大多数TCP/IP应用;
  • 对于部署在服务器上的应用来说,不需要修改任何代码就能实现不同机器上的应用访问;
  • 很多DNS系统还支持基于地理位置的域名解析,可以将域名解析成距离用户地理位置最近的服务器地址,加快用户访问速度。

但基于DNS的负载均衡同样也存在一些弊端:

  • 目前的DNS系统是需要经过递归服务器、顶级服务器、权威服务器以及众多缓存等多级解析的,在每一个环节都可能存在解析记录缓存。如果服务器IP发生变动,即使修改了A记录,也需要各级缓存失效后才能生效。而在解析生效前的这段时间,用户可能就会根据缓存记录访问到已经被更换过的服务器上,从而导致访问失败。
  • DNS负载均衡采用的是简单的轮询算法,不能区分不同服务器之间的性能和负载差异,不能反映服务器当前的运行状态,所以负载均衡效果并不太好。
  • 为了本地DNS服务器能够及时同步权威服务器上的最新记录,所以一般将DNS缓存刷新时间设置得比较小,这就会导致DNS频繁发起解析请求,从而造成额外的网络问题。

所以一些大型网站总是使用DNS域名解析作为第一级负载均衡手段,然后在通过提供负载均衡服务的内部服务器再进行负载均衡,将最终请求发到真实的服务器上,从而完成最终请求。

2. 浏览器根据IP地址与服务器建立socket连接

建立连接——三次握手

知道了服务器的IP地址,便可开始与服务器建立连接了,通信连接的建立需要经历以下三个过程:

  1. 客户端首先发送一个带有SYN标志的数据包给服务端(您好,我想认识你);
  2. 服务端接受SYN数据包之后,回传一个SYN/ACK标志的数据包以示传达确认连接信息(好的,很高兴认识你);
  3. 客户端收到SYN/ACK的确认数据包之后,再回传一个ACK标志的数据包给服务端,表示‘握手’结束(我也很高兴认识你),至此,客户端便与服务器建立了连接。

说明:

  • TCP协议:三次握手的过程采用TCP协议,其可以保证信息传输的可靠性,三次握手过程中,若一方收不到确认信息,协议会要求重新发送信号。

TCP的作用是啥?

  • 提供无差错的数据传输
  • 按序传输(数据总是会按照发送顺序到达)
  • 未分段的数据流(可以在任意时刻以任意尺寸将数据发送出去)

3. 浏览器与服务器通信:浏览器发出请求、服务器处理请求、渲染

当服务器与客户端建立了连接之后,客户端便开始与服务器进行通信。 网页请求是一个客户端向服务器请求数据==>服务器返回相应数据的单向的请求过程。

  • 浏览器根据URL生成HTTP请求,请求中包含请求文件的位置、请求文件的方式等信息;
  • 服务器接到请求后,会根据HTTP请求中的信息来决定如何获取相应的HTML文件;
  • 服务器将得到的HTML文件发送给浏览器;
  • 在浏览器还没有完全接受完HTML文件时便开始渲染、显示页面
  • 在执行HTML中代码时,根据需要,浏览器会继续请求图片、CSS、Javascript、视频、音频等文件,过程类似。

针对浏览器渲染、显示页面的过程,说明如下:

  • 浏览器端是一个边解析边渲染的过程。
  • HTML Parser将HTML内容解析为DOM Tree,CSS Parser将CSS内容解析为样式规则(Style Rules);
  • 根据样式规则和DOM Tree来渲染树(Render Tree),在这个渲染树的过程中会发生回流(layout/reflow/relayout),回流就是浏览器计算各个盒模型的位置、大小等属性的过程;
  • 等浏览器确定了盒模型的位置、尺寸等数据后开始绘制页面,这个过程称为重绘(Painting/repaint)。

4. 浏览器与服务器断开连接

断开连接——四次挥手

  • 客户端向服务端先发送一个带有FIN标志的数据包(我想关闭);
  • 服务端接受FIN数据包之后,回传一个ACK的数据包给客户端以示传达确认关闭信息(知道了:只是表示确认我知道你想要关闭了,但是我可能还有事还在处理,不一定现在就关)
  • 服务端向客户端发送一个FIN标志的数据包,请求关闭连接(我处理好了,可以关闭了)
  • 客户端收到FIN的数据包之后,回传一个ACK的数据包给服务端,以表示确认关闭(好的,那我关了),服务器收到确认信号后断开连接。

说明:

  • 为什么服务器在接到断开请求时不立即同意断开:当服务器收到断开连接的请求时,可能仍然有数据未发送完毕,所以服务器先发送确认信号,等所有数据发送完毕后再同意断开;
  • 第四次挥手后,主机发送确认信号后并没有立即断开连接,而是等待了2个报文传送周期,原因是:如果第四次挥手的确认信息丢失,服务器将会重新发送第三次挥手的断开连接的信号,而服务器发觉丢包与重新发送断开连接到达主机的时间正好为2个报文传输周期。