域名解析
在浏览器地址栏输入url并回车后,需要先把url地址解析为对应的ip地址才能发起HTTP请求
-
浏览器搜索自身DNS缓存,查找url对应ip地址,缓存时间为TTL属性决定
-
如果未命中,则搜索本地操作系统hosts文件并读取,查找url对应ip地址
-
如果未命中,则从路由器中DNS缓存文件中读取,查找url对应ip地址
-
如果未命中,则向操作系统配置的首选DNS服务器(通常为ISP(互联网服务供应商)LDNS(本地DNS)服务器)发送域名解析请求,该DNS服务器会在其本地的缓存中查找url的ip地址
-
如果未命中,则由首选DNS服务器迭代发送域名解析请求,以www.domain.com为例
-
从全球13台根域名服务器 返回.com 顶级域名服务器地址
-
从.com 顶级域名服务器 返回 domain.com权限域名服务器地址
-
从domain.com服务器递归查找完整url即www.domain.com的主机服务器地址
-
将url的ip地址返回给浏览器
-
建立TCP/IP连接
在获取了url的ip地址后,浏览器会通过一个1024到65535的随机端口向ip地址上的web服务器(httpd,node,nginx等)的80端口发起TCP连接请求。
连接请求将原HTTP请求经过TCP/IP 4层模型封包,(通过路由设备)送达服务器主机。经过服务器网卡进入到服务器内核TCP/IP协议栈(将TCP连接请求解包),(经过内核Netfilter防火墙模块)最终到达web应用,建立TCP/IP连接。
TCP/IP 4层模型:
- 访问层:为网络层提供访问接口,使其能够传递IP分组。
- 网络层:将IP分组发送到目标主机(IP协议)。
- 传输层:实现发送端到目标端对话(TCP协议)。
- 应用层:HTTP,Telnet,FTP等。
TCP三次握手
-
Client发送一个连接试探,Client进入syn_sent状态,等待服务器的回复。
-
SYN=1 表示这是一个连接请求/接受TCP报文,不能携带数据
- SEQ=x 表示Client 初始序列号
-
- Server收到连接请求报文后,如同意建立连接,则向Client发送确认,Server进入syn_rcvd状态,等待Client确认。
- SYN=1 同上
- ACK=x+1 表示期望收到对方下一个报文分段的第一个数据字节序号是x+1,x为已经正确接收的对方数据字节序列号(即Client发送的SEQ)
- SEQ= y 表示Server 初始序列号
- Client收到确认后还需再次发送确认,一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。
- SEQ = x+1 表示Client 数据字节序列号(与从Serve接收到的ACK保持一致)
- ACK = y+1 表示期望收到对方下一个报文分段的第一个数据字节序号是y+1,y为已经正确接收的对方数据字节序列号(即Serve发送的SEQ)
初始序列号( initial sequence number 即 ISN)是一个由ISN生成器为产生的32位序列号。
ISN生成器通过维护一个32位长、每4µs自增一次的时钟,来生成ISN。
由于
2^32
位的计数器,需要2^32*4 µs
自增完成,故可算出2^32*4 /(1*60*60*1000*1000)=4.772185884,即ISN大约每4.55小时循环一次。
由于在网络中最大分段寿命(Maximum Segment Lifetime (MSL) )默认2分钟,比4.55小时要短,故可认为 ISN 是唯一的。
由于无法实现全网统一的SEQ,故客户端和服务端在建立连接时需要分别发送自身维护的SEQ给对方。
通过TCP三次握手可以判断通信双方是否遵循TCP/IP协议,确保通信是可靠的,否则无法建立通信连接。
HTTP请求
HTTP协议采用请求-响应模式,大大简化了开发。当我们编写一个页面时,我们只需要在HTTP请求中把HTML发送出去,不需要考虑如何附带图片、视频等,需要的图片视频资源浏览器会代替程序另外发送HTTP请求来获取,因此一个HTTP请求只处理一个资源。
HTTP协议同时具备极强的扩展性,例如当浏览器请求http://www.domain.com/index.html时
,index.html
中可以通过链入的其他服务器的资源(如<img src="http://img.domain.com/static/index_bg.png">
)来分散请求压力到多个服务器,一个站点可以链接到其他站点,无数个站点互相链接起来,形成World Wide Web,即WWW。
HTTP请求方式
HTTP请求/响应报文
HTTP状态码
HTTP请求获得的响应数据类型由响应头Content-Type
属性确定,如果是网页,响应数据就是文本,如果是图片,响应数据就是图片的二进制数据。当存在Content-Encoding
时,响应数据数据是被压缩的,最常见的压缩方式是gzip,当看到Content-Encoding: gzip
时,需要将Body数据先解压缩,才能得到真正的数据。压缩的目的在于减少响应数据的大小,加快网络传输。
服务器向客户端返回请求数据之后,就要关闭 TCP 连接,如果客户端或者服务器在其头信息加入了这行代码 Connection:keep-alive ,TCP 连接在数据发送完成后将仍然保持打开状态,客户端可以继续通过同一连接发送请求,当该连接达到连接最长保持时间时才会断开,这节省了发送多个请求时建立0新连接所需的时间,避免了反复进行握手造成的性能和网络浪费。
关闭连接前会进行TCP四次挥手已确认数据传输完成。
TCP四次挥手
- 客户机向服务器发送自身
FIN
,请求关闭连接,进入fin_wait1状态,只收不发。 - 服务器向客户机
返回对方FIN(即ACK),进入
close_wait状态,确认客户机关闭资源请求,并继续等待客户端的所有请求完成。 - 服务器向客户机发送自身
FIN
,进入Last_Ack状态。 - 客户机向服务器发送自身
ACK
,客户机确认服务器响应,关闭连接。
四次挥手与三次握手最大区别在于三次握手中第二步实际是四次挥手中第二、三步的合并,由于断开连接时需要等待客户端的所有请求完成,所以拆分了这两步操作,减少连接时间,避免数据连接长期维护的性能浪费。
浏览器解析html代码 请求相关资源
浏览器从响应的body中获取index.html文件的源码后,开始解析其中的html代码,当解析到js/css/image等静态资源时,会自动为每一个资源发送新的HTTP请求到服务器端获取该资源下载(使用多线程下载,每个浏览器的线程数不一样,通常为4到8个),如果下载时间超过keep-alive设置的超时时间的该资源获取失败。
浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。
在一次HTTP连接中请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于资源大小不同、浏览器多线程下载、本地缓存资源直接读取,导致显示的顺序可能和代码里的顺序不一致。
浏览器渲染引擎对页面进行渲染
- 解析html内容,将html标签转化为DOM节点,生成DOM树
- 解析外部CSS资源和style标签中的样式信息并生成样式规则
- 使用样式规则将DOM树构建成render树
- 遍历render树,计算每一个元素的位置大小颜色层级等,将计算结果绘制并展现出来
值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
总结
域名解析
--> 发起TCP的3次握手
--> 建立TCP连接后发起http请求
--> 服务器响应http请求,浏览器得到html代码
--> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等)
--> 浏览器对页面进行渲染呈现给用户
.