这是一道经典的面试题,这道面试题不光前端面试会问到,后端面试也会被问到。这道题没有一个标准的答案,它涉及很多的知识点,面试官会通过这道题了解你对哪一方面的知识比较擅长,然后继续追问看看你的掌握程度。当然我写的这些也只是我的一些简单的理解,从前端的角度出发,我觉得首先回答必须包括几个基本的点,然后在根据你的理解深入回答。
- 浏览器的地址栏输入url并且按下回车
- 浏览器查找当前url是否存在缓存,并且比较缓存是否过期( 浏览器先查看浏览器缓存—系统缓存—路由器缓存 ,如果缓存中有,会直接在屏幕上面显示页面内容,如果没有,直接跳转到第三步)
- DNS解析(也称为域名解析)URL对应的IP地址
- 浏览器向服务器发送TCP连接,建立TCP连接(三次握手)
- 握手成功后,浏览器向服务器发起HTTP请求,请求数据包
- 服务器处理接收到的请求,将数据返回到浏览器,浏览器接收HTTP响应
- 读取页面内容,渲染页面,构建DOM树
- 关闭TCP连接(四次挥手)
一.URL
我们常见的URL是这样的:https://baike.baidu.com,这个域名有三部分组成:协议、域名、端口号,这里端口号是默认的,所以隐藏。除此之外,URL还会包含一些路径、查询和其他片段,例如:https://baike.baidu.com/item/%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B/5111559。我们常见的协议有HTTP协议,还有加密的HTTPS协议,FTP协议,FILE协议等。URL的中间部分分为域名或者IP,之后就是端口了。通常端口号不常见是因为大部分的都是使用的默认端口,如HTTP协议默认的端口号是80,HTTPS协议默认的端口号是443。
二.缓存
- 浏览器缓存:浏览器会记录DNS一段时间,因此,只是第一个地方解析DNS请求;
- 操作系统缓存:如果在浏览器缓存中不包含这个记录,则会使系统调用操作系统,获取操作系统的记录(保存最近的DNS查询缓存);
- 路由器缓存:如果上述两个步骤均不能成功获取DNS记录,继续搜索路由器缓存;
我们说说浏览器缓存,HTTP缓存有多种规则,根据是否需要重新向服务器发起请求来分类,我将其分为强制缓存,对比缓存。
强制缓存判断HTTP首部字段:cache-control,Expires。
Expires是一个绝对时间,即服务器时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。但是该方法存在一个问题:服务器时间与客户端时间可能不一致。因此该字段已经很少使用。
cache-control中的max-age保存一个相对时间。例如Cache-Control: max-age = 484200,表示浏览器收到文件后,缓存在484200s内均有效。 如果同时存在cache-control和Expires,浏览器总是优先使用cache-control。
对比缓存通过HTTP的last-modified,Etag字段进行判断。
last-modified是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送if-modified-since字段。服务器用本地Last-modified时间与if-modified-since时间比较,如果不一致则认为缓存已过期并返回新资源给浏览器;如果时间一致则发送304状态码,让浏览器继续使用缓存。
Etag:资源的实体标识(哈希字符串),当资源内容更新时,Etag会改变。服务器会判断Etag是否发生变化,如果变化则返回新资源,否则返回304。

三、DNS(域名)解析
我们知道在地址栏输入的域名并不是最后资源所在的真实位置,域名只是与IP地址的一个映射。网络服务器的IP地址那么多,我们不可能去记一串串的数字,因此域名就产生了,域名解析的过程实际是将域名还原为IP地址的过程。
首先浏览器先检查本地hosts文件是否有这个网址映射关系,如果有就调用这个IP地址映射,完成域名解析。
如果没找到则会查找本地DNS解析器缓存,如果查找到则返回。
如果还是没有找到则会查找本地DNS服务器,如果查找到则返回。
最后迭代查询,按根域服务器 ->顶级域,.cn->第二层域,hb.cn ->子域,www.hb.cn的顺序找到IP地址。

递归查询,按上一级DNS服务器->上上级->....逐级向上查询找到IP地址。

四、TCP连接
在通过上一步的DNS域名解析后,获取到了服务器的IP地址,在获取到IP地址后,便会开始建立一次连接,这是由TCP协议完成的,主要通过三次握手进行连接。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。

五、浏览器向服务器发送HTTP请求
完整的HTTP请求包含请求起始行、请求头部、请求主体三部分。
HTTP头字段包括4类:
general-header ;
request-header ;
response-header ;
entity-header .
————————————————————————————————————————————————————————
general header是request、response都可用的, 但是不能用于entity.
request-header fields 允许客户端传递关于request和客户端的附加信息到服务端,
response-header fields 允许服务端传递关于response的、不能放到Status-Line的附加信息。
这些头给出关于服务端的信息。
—————————————————————————————————————————————————————————
表1 公共头部

| 字段 | 说明 |
| Remote Address | 请求的远程地址 |
| Request URL | 请求的域名 |
| Request Method | 页面请求的方式:GET/POST |
| Status Code | 请求的返回状态 |
| Referrer Policy | 用于过滤 Referrer 报头内容,当发生降级(比如从 https:// 跳转到 http:// )时,不传递 Referrer 报头。 |
表2 请求头

| 字段 | 说明 |
| Accept | 表示浏览器支持的 MIME 类型 |
| Accept-Encoding | 浏览器支持的压缩类型 |
| Accept-Language | 浏览器支持的语言类型,并且优先支持靠前的语言类型 |
| Cache-Control | 指定请求和响应遵循的缓存机制 |
| Connection | 当浏览器与服务器通信时对于长连接如何进行处理:close/keep-alive |
| Cookie | 向服务器返回cookie,这些cookie是之前服务器发给浏览器的 |
| Host | 请求的服务器URL |
| Referer | 该页面的来源URL |
| If-Modified-Since | 服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 。 |
| If-None-Match | Etag是属于HTTP 1.1属性,它是由服务器生成返回给前端, 当你第一次发起HTTP请求时,服务器会返回一个Etag,并在你第二次发起同一个请求时,客户端会同时发送一个If-None-Match,而它的值就是Etag的值(此处由发起请求的客户端来设置)。 然后,服务器会比对这个客服端发送过来的Etag是否与服务器的相同, 如果相同,就将If-None-Match的值设为false,返回状态为304,客户端继续使用本地缓存,不解析服务器返回的数据(这种场景服务器也不返回数据,因为服务器的数据没有变化嘛) |
| User-Agent | 用户客户端的一些必要信息 |
| Upgrade-Insecure-Requests: | 用来向服务器端发送信号,表示客户端优先选择加密及带有身份验证的响应 |
表3 返回头

| 字段 | 说明 |
| Cache-Control | 告诉浏览器或者其他客户,什么环境可以安全地缓存文档 |
| Connection | 当client和server通信时对于长链接如何进行处理 |
| Content-Encoding | 数据在传输过程中所使用的压缩编码方式 |
| Content-Type | 数据的类型 |
| Date | 数据从服务器发送的时间 |
| Etag | Etag 是URL的Entity Tag,用于标示URL对象是否改变。ETag:"50b1c1d4f775c61:df3"客户端的查询更新格式是这样的:If-None-Match : W / "50b1c1d4f775c61:df3"如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。 |
| Expires | 应该在什么时候认为文档已经过期,从而不再缓存它? |
| Server | 服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置 |
| Set-Cookie | 设置和页面关联的cookie |
| Transfer-Encoding | 数据传输的方式 |
| vary | 它决定了对于未来的一个请求头,应该用一个缓存的回复(response)还是向源服务器请求一个新的回复。 |

六、浏览器接收响应
服务器在收到浏览器发送的HTTP请求之后,会将收到的HTTP报文封装成HTTP的Request对象,并通过不同的Web服务器进行处理,处理完的结果以HTTP的Response对象返回,主要包括状态码,响应头,响应报文三个部分。
状态码主要包括以下部分
1xx:指示信息–表示请求已接收,继续处理。
2xx:成功–表示请求已被成功接收、理解、接受。
3xx:重定向–要完成请求必须进行更进一步的操作。
4xx:客户端错误–请求有语法错误或请求无法实现。
5xx:服务器端错误–服务器未能实现合法的请求。
响应头主要由Cache-Control、 Connection、Date、Pragma等组成。
响应体为服务器返回给浏览器的信息,主要由HTML,css,js,图片文件组成。
七、页面渲染
如果说响应的内容是HTML文档的话,就需要浏览器进行解析渲染呈现给用户。整个过程涉及两个方面:解析和渲染。在渲染页面之前,需要构建DOM树和CSSOM树。


在浏览器还没接收到完整的 HTML 文件时,它就开始渲染页面了,在遇到外部链入的脚本标签或样式标签或图片时,会再次发送 HTTP 请求重复上述的步骤。在收到 CSS 文件后会对已经渲染的页面重新渲染,加入它们应有的样式,图片文件加载完立刻显示在相应位置。在这一过程中可能会触发页面的重绘或重排。这里就涉及了两个重要概念:Reflow和Repaint。
Reflow,也称作Layout,中文叫回流,一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为Reflow。
Repaint,中文重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等),此时只需要应用新样式绘制这个元素就OK了,这个过程称为Repaint。
所以说Reflow的成本比Repaint的成本高得多的多。DOM树里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。
下面这些动作有很大可能会是成本比较高的:
-
增加、删除、修改DOM结点时,会导致Reflow或Repaint
-
移动DOM的位置,或是搞个动画的时候
-
内容发生变化
-
修改CSS样式的时候
-
Resize窗口的时候(移动端没有这个问题),或是滚动的时候
-
修改网页的默认字体时
基本上来说,reflow有如下的几个原因:
-
Initial,网页初始化的时候
-
Incremental,一些js在操作DOM树时
-
Resize,其些元件的尺寸变了
-
StyleChange,如果CSS的属性发生变化了
-
Dirty,几个Incremental的reflow发生在同一个frame的子树上
八、关闭TCP连接或继续保持连接
四次挥手,别名连接终止协议。其性质为终止协议。
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端。
(4) 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
通过四次挥手关闭连接(FIN ACK, ACK, FIN ACK, ACK)。

第一次挥手是浏览器发完数据后,发送FIN请求断开连接。
第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN应该放在第三次挥手中。
这样浏览器需要返回ACK表示同意,也就是第四次挥手。
至此从浏览器地址栏输入URL到页面呈现到你面前的整个过程就分析完了,上面内容如有错误欢迎留言交流。
本文详细解析了从在浏览器地址栏输入URL到页面完全加载呈现的全过程,涵盖DNS解析、TCP连接、HTTP请求与响应、页面渲染等核心环节,揭示了网络请求背后的复杂机制。
4109

被折叠的 条评论
为什么被折叠?



