地址栏输入url后发生了什么?
从地址栏输入url到页面显示的整个过程
1、浏览器解析URL,提取域名、端口号以及请求资源的路径;
2、通过域名服务系统(DNS)获取域名对应的目标服务器的IP地址;
3、得到目标服务器的IP地址以及端口号(如果没有端口号,http的默认端口号是80,https是443)后,建立TCP连接;
4、浏览器发送http请求;
5、服务器响应请求,请求的资源在响应报文主体中;
6、若双方都不需要传输数据,就断开TCP连接;
7、浏览器开始渲染页面,浏览器将HTML文档解析为DOM树,处理CSS并构建CSSOM(CSS对象模型)树;
8、将DOM树根CSSOM树结合在一起,也即为每个节点附加样式,构建Render树(渲染树);
9、布局,从渲染树根节点开始遍历,计算每个节点的尺寸大小以及在浏览器窗口的确切位置;
10、绘制,浏览器将布局阶段计算出的每个节点的框体转换为屏幕上的实际像素,呈现到屏幕上。
注意:对于上述的页面渲染过程,其实并不是按顺序一次性完成的。因为HTML文档中的JavaScript代码和CSS样式可能会多次修改DOM或CSS对象,从而引起页面的回流或重绘。
URL结构
域名解析过程
假定域名主机想要访问www.baidu.com,流程如下:
1、首先搜索浏览器的DNS缓存,看是否有www.baidu.com对应的IP地址。
2、若没有命中,则继续搜索操作系统的DNS缓存,操作系统的DNS缓存其实是用户自己配置的hosts文件。
3、若仍然没有命中。则将域名发送给本地域名服务器dns.xyz.com。若查询成功则返回结果;否则,本地域名服务器以DNS客户的身份向其他根域名服务器继续发送查询请求(代替主机),而不是让主机自己进行下一步的查询操作(称为递归查询)。
4、根域名服务会告诉本地域名服务器下一步应该向哪一个顶级域名服务器查询,也即根域名服务器会返回一个顶级域名服务器的IP地址。
5、本地域名服务器有了这个IP地址后,向对应的顶级域名服务器查询,若有www.baidu.com的IP地址,则直接返回给本地域名服务器;否则,告诉本地域名服务器下一步应该查询的权限域名服务器的地址。
6、本地域名服务器向权限域名服务器查询,最终得到该域名对应的IP地址 。
7、本地域名服务器将IP地址发送给主机,主机的操作系统将IP地址缓存起来。
8、操作系统将IP地址发送给浏览器,浏览器的DNS缓存将IP地址缓存起来。
TCP连接的三次握手
TCP三次握手建立连接
1、最初,客户端A和服务器B都处于CLOSED(关闭)状态,假设由服务器B先进入LISTEN(监听)状态,等待客户端A的连接;
2、第一次握手:客户端A向服务器B发出连接请求报文段,首部的同步位SYN=1,同时选择一个初始序列seq=x,这时客户端A进入SYN-SET(同步已发送)状态;
3、第二次握手:服务器B收到连接请求报文段后,如同意连接则向客户端A发出确认。确认报文段中,SYN=1,ACK=1,确认号ack=x+1,同时为自己选择一个初始序列seq=y,服务器B进入SYN-RCVD(同步收到)状态;
4、第三次握手:客户端A收到来自服务器B的确认后,需要再次发送确认报文段,ACK=1,确认号ack=y+1,序号为seq=x+1.客户端A进入ESTABLISHED(已建立连接)状态;
5、当服务器B收到来自客户端A的确认报文段后,也进入ESTABLISHED状态,此时双方可以进行数据传输。
三次握手中,为什么最后还要发送一次确认?(为什么要使用三次握手?)
目的是防止已失效的连接请求报文又发送到了服务器B,使得服务器B误以为客户端A发出了新的连接请求,从而向客户端A发送确认。假设不使用三次握手,那么在服务器B看来这里有两条TCP连接在进行,但在客户端A看来自己并没有发出新的连接请求,因此不会向新的连接传输数据,而服务器B的第二条TCP连接则一直等待客户端A传输数据,造成资源的浪费。若采用三次握手,在服务器B收到失效报文段后发出第二次确认时,客户端A不会对此次确认报文段进行确认,那么服务器B就收不到第三次握手时由客户端发来的确认报文段,这样服务器B就知道客户端A没有要求新的连接请求。
所谓的“已失效的连接请求”,指的是客户端A发出的第一个连接请求报文段并没有丢失,但在某些网络节点中滞留了,此时客户端A会进行超时重传,发出第二个连接请求报文段。然而,过了段时间后,滞留的第一个连接请求报文段也到达了服务器B。
TCP连接的四次挥手
TCP四次挥手释放连接
1、第一次挥手:数据传输结束后,双方仍处于ESTABLISHED状态。假设由客户端A先发出连接释放报文段,客户端A先停止数据传输并主动关闭TCP连接。连接释放报文段中,FIN=1,seq=u(序列号为客户端A前面已传输数据的最后一个字节的序号加1)。此时,客户端A进入FIN-WAIT-1(终止等待1)状态;
2、第二次挥手:服务器B收到连接释放报文段后发出确认,ACK=1,确认号ack=u+1,seq=v(序列号为服务器B前面已传输数据的最后一个字节的序号加1)。这时服务器B进入CLOSE-WAIT(关闭等待)状态,由客户端A到服务器B这个方向的TCP连接就关闭了,但服务器B要传输数据时客户端A仍可接收;
3、客户端A收到服务器B的确认后,进入FIN-WAIT-2(终止等待2)状态,等待服务器B发出连接释放请求;
4、第三次挥手:当服务器B已经没有要向客户端A发送的数据时,则向客户端A发出连接释放报文段,FIN=1,ACK=1,seq=w,ack=u+1(重复上次已发送的确认号),这时服务器B进入LAST-ACK(最后确认)状态;
5、第四次挥手:客户端A收到连接释放报文段后发出确认,ACK=1,ack=w+1,seq=u+1。这时客户端A进入TIME-WAIT(时间等待)状态,经过计时器设定的2MSL(MSL称为最长报文段寿命,2MSL也即一个报文段的来回时间)后进入CLOSED状态,而服务器B收到确认后也进入CLOSED状态。
为什么TIME-WAIT状态必须等待2MSL?
为了保证客户端A发送的最后一个ACK报文能够到达B。因为ACK报文可能丢失,使得处于LAST-ACK状态下的服务器B收不到确认时会重传FIN报文,那么客户端A就能在2MSL时间内收到这个重传的FIN报文,从而重发一次确认,使得双方都能进入CLOSED状态。如果客户端在TIME-WAIT状态中不等待,而是直接进入CLOSED状态,那么在最后一个ACK报文丢失的情况下,客户端A就收不到服务器B重传的FIN报文,服务器B也就无法收到客户端A对重传FIN报文的确认,从而导致服务器B无法进入CLOSED状态。
另外,设置2MSL也能防止已失效的连接请求报文段。因为客户端A发送完最后一个ACK报文后,在等待的2MSL时间内,本连接产生的所有报文段都会到达寿命,使下一次TCP连接中不会出现旧的连接请求报文段。
为什么需要四次挥手?可以改成三次吗?
因为TCP是全双工通信的,使用四次挥手可以使得连接释放过程中只关闭一个方向的TCP连接,也即“半关闭状态”。比如,客户端到服务器这个方向的TCP连接关闭后,服务器可能还有数据需要处理和发送,此时客户端仍然可以接收来自服务器的数据。
如果客户端请求释放连接时,服务器也没有数据需要传输了,此时将第二次挥手与第三次挥手合并,则可以改成三次挥手。
回流(reflow)与重绘(repaints)
回流:对节点大小和位置的重新计算称为“回流”,或者称为“重排”;回流一定会导致重绘。
重绘:当元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程称为“重绘”。
何时发生回流?
1、页面首次渲染;
2、添加或删除可见的DOM元素;
3、元素的位置或尺寸发生变化;
4、浏览器窗口尺寸发生改变;
5、查询某些属性,如offset前缀的属性、scroll前缀的属性、client前缀的属性等,或者调用某些方法时会触发,如getCoumputedStyle()。
注意:通常,浏览器的优化机制会维护一个队列来实现批量执行重排或重绘操作,当达到一定的时间时或者队列中的重排重绘操作数量达到一个阈值时,才清空队列,一次性执行这些操作。但当我们使用scrollTop等获取布局信息的属性时,由于需要获取到页面的最新布局信息,因此会强制这个队列刷新,导致提取重排重绘。
如何减少重排和重绘?
1、修改元素的多个样式时,通过更换类名的方式集中改变样式,而不是通过操作元素的style属性来多次修改;
2、当需要批量操作DOM时,
方法一:先给元素设置display:none样式,元素便不会存在渲染树中。然后对该元素进行批量操作后,再通过修改display属性来显示,整个过程仅触发两次重排;
方法二:使用JavaScript动态插入多个节点时,可以使用documentFragment API创建一个文档片段,在它上面批量操作DOM后,再将该片段添加进文档中,只触发一次重排;
方法三:将原始元素拷贝到一个脱离文档流的节点中,批量操作完后再替换原始元素;
3、避免使用table布局,table中每个元素的大小及内容的改动都会导致整个table重新计算;
4、对于复杂的动画,可以设置position:absolute或fixed使其脱离文档流,减少对其他元素的影响;
5、启动CSS3的GPU硬件加速,可以让transition、transform、Canvas2D这些动画交给GPU完成,不会触发回流和重绘;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)