文章目录
前言
- 浏览器中输入URL返回页面全过程
- DNS域名解析过程
- TCP的三次握手、四次挥手
一、浏览器中输入域名
二、解析域名
2.1 具体过程
2.2 知识补充
- 2.2.1 域名体系结构
- 2.2.2 查询方式——递归查询、迭代查询
- 2.2.3 DNS域名解析过程
三、浏览器与目标服务器建立TCP连接
3.1 详解
3.2 知识补充
- 3.2.1 TCP 与 UDP
- 3.2.2 TCP的三次握手
- 3.2.3 TCP的四次挥手
四、浏览器发送HTTP请求
五、服务器响应HTTP请求
六、TCP释放连接(TCP四次挥手)
七、浏览器解析响应内容,处理和渲染
八、总结
前言
浏览器中输入URL返回页面全过程
在软件开发、Java、后端的面试中,浏览器中输入URL到页面返回的全过程 是一道非常经典的面试题,更是经常被作为面试的压轴题出现。有时也会通过其他方式来问,譬如:
- 前端发起请求之后到达后端,中间过程是什么
- 当你输入一个网址时,实际会发生什么
本质上为同一个问题,具体分为7个步骤:
- 浏览器中输入域名
- 解析域名,找到主机ip
- 浏览器与目标服务器建立TCP连接。浏览器利用IP直接与网站主机通信,三次握手、建立TCP连接。浏览器会以一个随机端口向服务端的web程序80端口发起TCP连接
- 浏览器通过http协议向目标服务器发送请求。建立TCP连接后,浏览器向主机发起一个HTTP请求
- 服务器响应请求,将对应数据返回给浏览器
- TCP释放链接
- 浏览器解析响应内容,进行渲染,呈现给用户
DNS域名解析过程
假定某客户机想获知域名为xxx.example.com主机的IP地址,域名解析的过程(共使用8个UDP报文)如下:
- 客户机向其本地域名服务器发出DNS请求报文
- 本地域名服务器收到请求后,查询本地缓存,若没有该记录,则以DNS客户的身份向根域名服务器发出解析请求
- 根域名服务器收到请求后,判断该域名属于.com域,将对应的顶级域名服务器dns.com的IP地址返回给本地域名服务器
- 本地域名服务器向顶级域名服务器dns.com发出解析请求报文
- 顶级域名服务器dns.com收到请求后,判断该域名属于example.com域,因此将对应的授权域名服务器dns.example.com的IP地址返回给本地域名服务器
- 本地域名服务器向授权域名服务器dns.example.com发起解析请求报文
- 授权域名服务器dns.example.com收到请求后,将查询结果返回给本地域名服务器
- 本地域名服务器将查询结果保存到本地缓存,同时返回给客户机
- 浏览器检查缓存,如果没有找到需要的IP地址,会向本地DNS服务器请求(递归查询)
- 本地DNS服务器如果没有对应的IP地址,会向根DNS服务器查询,进而迭代向顶级域名服务器、权限域名服务器查询,直到获取到目标服务器的IP地址,并返回给浏览器(迭代查询)
TCP的三次握手、四次挥手
见本文3.2.2、3.2.3小节。
一、浏览器中输入域名
浏览器中输入域名 www.baidu.com,客户端发起请求。
二、解析域名
2.1 具体过程
浏览器会把输入的域名解析成对应的IP,过程如下:
- 查询缓存:浏览器会先查找当前URL的缓存记录(浏览器缓存、系统缓存、路由缓存),看是否有域名对应的IP地址。如存在缓存,就直接显示;如果没有,接着下一步
- 浏览器缓存:简单来说,浏览器缓存就是把一个已经请求过的Web资源(如html页面,图片,js,数据等)拷贝一份副本储存在浏览器中。
- 操作系统缓存:浏览器缓存中没有记录,再到本地操作系统缓存中查询,一般在本机hosts文件(如有直接获取)
- 路由缓存:路由器也有DNS缓存(如有直接获取)
- 接着是对本地DNS服务器进行递归查询,看是否有域名对应的IP。主机向本地域名服务器的查询一般都是采用递归查询。所谓递归查询就是如果主机所询问的本地域名服务器不知道被查询域名的IP地址,那么本地域名服务器就以DNS客户的身份,向其他根域名服务器继续发出查询请求报文,而不是让该主机自己进行下一步查询。(本地域名服务器地址是通过DHPC协议获取地址,DHPC是负责分配IP地址的)
- 本地域名服务器采用迭代查询,它先向一个根域名服务器查询。本地域名服务器向根域名服务器的查询一般都是采用迭代查询。所谓迭代查询就是当根域名服务器收到本地域名服务器发出的查询请求报文后,要么告诉本地域名服务器下一步应该查询哪一个域名服务器,然后本地服务器自己进行后续的查询。(而不是替代本地服务器进行后续查询)
- 根域名服务器告诉本地域名服务器,下一次应查询的顶级域名服务器dns.com的IP地址(有关各域名服务器的关系 可见下面2.2.1小节)
- 本地域名服务器向顶级域名服务器dns.com进行查询
- 顶级域名服务器dns.com告诉本地域名服务器,下一次应查询的权限域名服务器dns.baidu.com的IP地址
- 本地域名服务器向权限域名服务器dns.baidu.com进行查询
- 权限域名服务器dns.baidu.com告诉本地域名服务器,所查询的主机www.baidu.com的IP地址。
本地域名服务器最后把查询结果告诉主机。
2.2 知识补充
2.2.1 域名体系结构
DNS服务协议采用类似目录树的层次结构记录域名与IP地址的映射对应关系,形成一个分布式的数据库系统:DNS 结构模型
域名空间的树状图:
域名组成图:
由高向低进行层次划分,可分为以下几大类:
分类 | 作用 |
---|---|
根域名服务器 | 最高层次的域名服务器,本地域名服务器解析不了的域名就会向其求助 |
顶级域名服务器 | 负责管理在该顶级域名服务器下注册的二级域名 |
权限域名服务器 | 负责一个区的域名解析工作 |
本地域名服务器 | 当一个主机发出DNS查询请求时,这个查询请求首先发给本地域名服务器 |
2.2.2 查询方式——递归查询、迭代查询
1、递归查询
递归查询是一种DNS服务器的查询模式,在该模式下DNS服务器接收到客户机请求,必须使用一个准确的查询结果回复客户机。如果DNS服务器本地没有存储查询DNS信息,那么该服务器会询问其他服务器,并将返回的查询结果提交给客户机
总的来说:就是客户机发送请求后自己只用等待结果即可,中间具体过程交给服务器实现
例子:当你在浏览器中输入一个网址时,你的计算机的DNS客户端会向本地DNS服务器发送一个递归查询请求,以获取该域名对应的IP地址
2、迭代查询
DNS服务器另外一种查询方式为迭代查询,当客户机发送查询请求时,DNS服务器并不直接回复查询结果,而是告诉客户机另一台DNS服务器地址,客户机再向这台DNS服务器提交请求,依次循环直到返回查询的结果为止
总的来说:客户机的请求需要自己挨个去查询才能得到结果,服务器没有结果时只会给你提供其它服务器的地址,而不会帮你去请求查询,这与递归查询截然相反
3、总结
从递归和迭代查询可以看出:
- 客户端-本地DNS服务器:这部分属于递归查询
- 本地DNS服务端----外网:这部分属于迭代查询
递归查询时,返回的结果只有两种:查询成功或查询失败
迭代查询又称作重指引,返回的是最佳的查询点或者主机地址
2.2.3 DNS域名解析过程
假定某客户机想获知域名为xxx.example.com主机的IP地址,域名解析的过程(共使用8个UDP报文)如下:
- 客户机向其本地域名服务器发出DNS请求报文
- 本地域名服务器收到请求后,查询本地缓存,若没有该记录,则以DNS客户的身份向根域名服务器发出解析请求
- 根域名服务器收到请求后,判断该域名属于.com域,将对应的顶级域名服务器dns.com的IP地址返回给本地域名服务器
- 本地域名服务器向顶级域名服务器dns.com发出解析请求报文
- 顶级域名服务器dns.com收到请求后,判断该域名属于example.com域,因此将对应的授权域名服务器dns.example.com的IP地址返回给本地域名服务器
- 本地域名服务器向授权域名服务器dns.example.com发起解析请求报文
- 授权域名服务器dns.example.com收到请求后,将查询结果返回给本地域名服务器
- 本地域名服务器将查询结果保存到本地缓存,同时返回给客户机
- 浏览器检查缓存,如果没有找到需要的IP地址,会向本地DNS服务器请求(递归查询)
- 本地DNS服务器如果没有对应的IP地址,会向根DNS服务器查询,进而迭代向顶级域名服务器、权限域名服务器查询,直到获取到目标服务器的IP地址,并返回给浏览器(迭代查询)
三、浏览器与目标服务器建立TCP连接
3.1 详解
- 主机浏览器通过DNS解析得到了目标服务器的IP地址后,与服务器建立TCP连接(浏览器会以一个随机端口向服务端的web程序80端口发起TCP连接)
- TCP三次握手建立连接:浏览器所在的客户机向服务器发出连接请求报文;服务器接收报文后,同意建立连接,向客户机发出确认报文;客户机接收到确认报文后,再次向服务器发出报文,确认已接收到确认报文;此处客户机与服务器之间的TCP连接建立完成,开始通信。
3.2 知识补充
3.2.1 TCP 与 UDP
什么是TCP? TCP是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- TCP:用于对传输准确性要求特别高的场景。如文件传输、发送和接收邮件、远程登录等
- UDP:一般用于即时通信。如语音、视频、直播等
TCP、UDP的区别(重要)
TCP | UDP |
---|---|
面向连接 | 无连接 |
提供可靠服务 | 不保证可靠交互 |
有状态 | 无状态 |
面向字节流 | 面向报文 |
传输效率较慢 | 传输效率较快 |
有拥塞控制 | 没有拥塞控制 |
每一条TCP连接只能是 | 支持一对一、一对多、多对一、多对多 |
首部开销20字节 | 首部开销8字节 |
运行于TCP、UDP上的协议
- 运行于TCP之上的协议:HTTP、HTTPS、FTP、SMTP、POP3/IMAP、Telnet、SSH
- 运行于UDP之上的协议
- DHCP:动态主机配置协议,动态配置IP地址
- DNS:域名系统(DNS,Domain Name System)将人类可读的域名(如www.baidu.com)转化为机器可读的IP地址(如220.181.38.148),可将其理解为专为互联网设计的电话簿。实际上DNS同时支持UDP、TCP
3.2.2 TCP的三次握手
假设发送端为客户端,接收端为服务端。开始客户端、服务端的状态都是CLOSED
- 第一次握手(无任何状态):客户端向服务端发起建立连接请求,客户端会随机生成一个起始序列号x,客户端向服务端发送的字段包含标志位SYN=1,序列号seq=x。第一次握手后客户端的状态为SYN-SENT。此时服务端的状态为LISTEN
- 第二次握手(保证:客户端的发送能力、服务器的接收能力没问题):服务端在收到客户端发来的报文后,会随机生成一个服务端的起始序列号y,然后给客户端回复一段报文,标志位SYN=1,序列号seq=y,ACK=1,确认号ack=x+1。第二次握手后服务端的状态为SYN-RCVD(SYN=1表示要和客户端建立一个连接,ACK=1表示确认序号有效)
- 第三次握手(保证:客户端的接收能力、服务器的发送能力没问题):客户端收到服务端发来的报文后,会再向服务端发送报文。ACK=1,序列号seq=x+1,确认号ack=y+1。客户、服务端状态变为ESTABLISTED。此时连接建立完成
A<-->B
第一个包,即A发给B的SYN中途被丢,没有到达B
- A会周期性超时重传,直到收到B的确认
第二个包,即B发给A的SYN+ACK中途被丢,没有到达A
- B会周期性超时重传,直到收到A的确认
第三个包,即A发给B的ACK中途被丢,没有到达B ——A发完ACK,单方面认为TCP为Established状态,而B显然认为TCP为Active状态
- a.假定此时双方都没有数据发送,B会周期性超时重传,直到收到A的确认
- b.假定此时收到A的数据发送,B收到A的Data+ACK,自然切换到established状态,并接受A的Data
- c.假定B有数据发送,数据发送不了,会一直周期性超时重传SYN+ACK,直到收到A的确认才可以发送数据
3.2.3 TCP的四次挥手
A的应用进程先向B发出连接释放报文段(FIN=1,Seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1状态。
B收到连接释放报文段后发送确认报文段(ACK=1,ack=u+1,seq=v),B进入CLOSE-WAIT状态,此时的TCP处于半关闭状态
A收到B的确认后,进入FIN-WAIT-2状态,等待B发出的连接释放报文段
B发送完数据,就发出连接释放报文段(FIN=1,seq=W,ACK=1,ack=u+1),B进入LAST-ACK状态
A收到B的连接释放报文段后,发出确认报文段(ACK=1,seq=u+1,ack=w+1),A进入TIME-WAIT状态。此时TCP未释放掉,需要经过时间等待计时器设置的2MSL(最大报文段生存时间)后,A进入C1OSE状态。B在收到A发出的确认报文段后关闭连接,若没收到则B会重传连接释放报文段
常见问题:
1)四次挥手为什么要等待2MSL?
保证A发送的最后一个ACK报文段能够达到B。这个ACK报文段可能丢失,B收不到这个确认报文,就会超时重传连接释放报文段,A可以在这个2MSL时间内收到这个重传的连接释放报文段,接着A重传一次确认,并重新启动2MSL计时器,最后A和B都进入CLOSED状态。若A在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段立即进入CLOSED,则无法收到B重传的连接释放报文段,那么A不会再发一次确认报文段,B就无法正常进入CLOSED状态
2)为什么是四次挥手?
TCP是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后 发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。
举个例子,A和B打电话
- 第一次挥手:A说“我没啥要说的了”
- 第二次挥手:B回答“我知道了”,但是B可能还会有要说的话,A不能要求B跟着自己的节奏结束通话
- 第三次挥手:于是B可能又巴拉巴拉说了一通,最后B说“我说完了”
- 第四次挥手:A回答“知道了”,这样通话才算结束
随机生成序列号的原因
- 提供安全性:防止TCP序列号预测攻击和会话劫持
- 避免旧连接干扰:确保新旧连接的隔离,防止旧数据包干扰新连接
- 增强网络可靠性:减少网络延迟和重新传输造成的混淆
四、浏览器发送HTTP请求
浏览器通过已建立的TCP连接,发送HTTP请求,请求报文包括三部分,请求行、请求头、请求体
请求行。例 POST /demo/index.html HTTP/1.1
- 请求方法。如get、post、put、delete、patch、head、options、trace
- URL
- 协议版本
请求头。请求头包含了请求的附加信息,一般以key:value的形式存在。比如关于客户端的信息,host(主机名)
请求体。请求体包含了多个请求参数的数据,包含了回车符、换行符、请求数据(不是所有的请求都带有请求数据)
浏览器向主机发起一个HTTP-GET方法报文请求。请求中包含访问的URL,也就是http://www.baidu.com/ ,KeepAlive,长连接,还有User-Agent用户浏览器操作系统信息,编码等。值得一提的是Accep-Encoding和Cookies项。Accept-Encoding一般采用gzip,压缩之后传输html文件。Cookies如果是首次访问,会提示服务器建立用户缓存信息,如果不是,可以利用Cookies对应键值,找到相应缓存,缓存里面存放着用户名,密码和一些用户设置项。
五、服务器响应HTTP请求
服务器收到请求后处理请求,并返回响应报文数据。
后端服务器接收到请求包,Web服务器(如Nginx、Apache等)处理基础的请求任务,如负载均衡、静态资源提供等
应用服务器处理请求
- Web服务器将请求转发给应用服务器(如Tomcat、Node.js等)
- 中间件(如Spring、Express等)处理路由和中间件函数,如验证、日志记录等
业务逻辑处理
- 应用服务器依据请求路径和参数,将请求分发到对应的业务处理逻辑中
- 可能会进行数据库查询、调用其他API服务、业务逻辑运算等操作。
- 数据库及外部系统交互:如果需要数据库查询,应用服务器会构造SQL语句或者请求ORM(对象关系映射)框架,数据库接收请求并返回结果;可能还会调用其他微服务或第三方API,并处理响应结果
构建响应
- 应用服务器完成业务处理后,构建HTTP响应,包括状态码、响应头和响应体
- 响应体可能是HTML页面、JSON数据、XML数据等。
发送响应:应用服务器将HTTP响应通过TCP连接发送回客户端。响应报文包含三部分
响应行:包含协议版本,状态码,状态码描述
响应头:包含一些附加的响应信息
响应主题:包含回车符、换行符和响应返回的数据(不是所有的响应都有响应数据)
补充:
1)如果报头中Content-type为“text/html”,浏览器以HTML形式呈现,而不是下载文件
2)对于大型网站存在多个主机站点,往往不会直接返回请求页面,而是重定向。返回的状态码就不是200OK,而是301,302以3开头的重定向码,浏览器在获取了重定向响应后,在响应报文中Location项找到重定向地址,浏览器重新第一步访问即可
3)重定向是为了负载均衡或者导入流量,提高SEO排名。利用一个前端服务器接受请求,然后负载到不同的主机上,可以大大提高站点的业务并发处理能力;重定向也可将多个域名的访问,集中到一个站点;由于baidu.com,www.baidu.com会被搜索引擎认为是两个网站,照成每个的链接数都会减少从而降低排名,永久重定向会将两个地址关联起来,搜索引擎会认为是同一个网站,从而提高排名
六、TCP释放连接(TCP四次挥手)
浏览器接收HTTP响应后,根据实际情况选择关闭TCP连接或者保留重⽤,关闭TCP连接的四次握⼿如下:
- 浏览器向服务器发送报文(Fin=1,Ack=z,Seq=x),表示客户端请求报文已经发送完了,准备关闭了。并进入到FIN_WAIT_1状态。,即断开连接的请求(太阳下山了,我该回家干饭了)到服务器
- 服务器收到客户端的断开请求后,发送确认报文(Ack=x+1,Seq=z),表示统一关闭。此时主机进入FIN_WAIT_2状态。,即服务器接到请求后发送确认收到请求的信号(哦,我知道了)
- 服务器在发送完数据以后,也会向客户端发送断开连接的报文(Fin=1,Ack=x,Seq=y),表示我没有响应数据要传了,准备关闭了。此时进入到LAST_ACK状态,即服务器向浏览器发送断开通知(你走吧,我也该回家抱娃了)
- 客户端收到服务器的关闭请求后,会发送一个确认报文(Ack=y+1,Seq=x),表示同意关闭。服务器收到客户单的确认报文后关闭连接。而浏览器在等待一段时间后未收到回复,则正常关闭。,即客户端接到断开通知后断开连接并反馈一个确认信号(嗯,走咯),服务器收到确认信号后也断开连接;
Tips:为什么不能三次挥手?有可能数据还未传输完成,所以服务器要先确认后再发起断开消息
简而言之:
- 浏览器所在主机向服务器发出连接释放报文,然后停止发送数据;
- 服务器接收到释放报文后发出确认报文,然后将服务器上未传送完的数据发送完;
- 服务器数据传输完毕后,向客户机发送连接释放报文;
- 客户机接收到报文后,发出确认,然后等待一段时间后,释放TCP连接
七、浏览器解析响应内容,处理和渲染
浏览器接收到HTTP响应,检查HTTP状态码,根据状态码决定后续处理,进行渲染,呈现给用户:
- 如果响应是HTML,浏览器启动HTML解析器解析页面,并请求html代码中的资源(如js、css、图片等)
- 浏览器接收到 HTTP 数据包后的解析流程(解析 html、 词法分析然后解析成 dom 树、解析 css ⽣成 css 规则树、合并成render 树,然后layout 、 painting 渲染、复合图层的合成、 GPU 绘制、外链资源的处理、 loaded 和 DOMContentLoaded 等)
- 如果响应是JSON数据,JavaScript代码处理数据并更新DOM或执行其他操
作。 - 进行后续资源的请求和加载(如CSS、JS文件)
八、总结
浏览器中输入URL返回页面过程,具体分为7个步骤:
- 浏览器中输入域名
- 解析域名,找到主机ip
- 浏览器与目标服务器建立TCP连接。浏览器利用IP直接与网站主机通信,三次握手、建立TCP连接。浏览器会以一个随机端口向服务端的web程序80端口发起TCP连接
- 浏览器通过http协议向目标服务器发送请求。建立TCP连接后,浏览器向主机发起一个HTTP请求
- 服务器响应请求,将对应数据返回给浏览器
- TCP释放链接
- 浏览器解析响应内容,进行渲染,呈现给用户
参考 浏览器中输入URL到页面返回的全过程、DNS域名解析服务、浏览器输入url后执行的整个过程(详细解析)、影子的知识文档