整体流程
域名解析 -> 与服务器建立连接 -> 发起HTTP请求 -> 服务器相应HTTP请求 -> 浏览器得到html代码 -> 浏览器解析html文件,创建DOM树 -> 解析CSS,创建CSS对象模型 -> 将CSS与DOM合并,构建渲染树(rendering tree)-> 布局和绘制
域名解析
首先会从浏览器自身DNS搜索,找到并且没有过期,则跳过域名解析过程,否则进行下一步
Chrome的DNS缓存大概1分钟缓存,且只能容纳100条;IE为30分钟;FireFox也为1分钟
从系统本地缓存DNS中搜索(使用 ipconfig /dispalydns),这个缓存有效期一般和DNS服务器返回的TTL时间有关,如果搜索到则跳过解析过程,否则进行下一步
查看系统的hosts文件中有没有该域名对应的ip地址,如果有,则跳过解析过程,否则进行下一步
向本地配置的首选DNS服务器发起域名解析,DNS服务器则会返回对应的ip地址
与服务器建立连接(TCP连接)
A 的 TCP 向 B 发出连接请求报文段,其首部中的同步比特 SYN 应置为1,并选择序号 x,表明传送数据时的第一个数据字节的序号是 x(设置初始段序号SEQ = x ,例如SEQ = 26 500)
B 的 TCP 收到连接请求报文段后,如同意,则发回确认。B 在确认报文段中应将 SYN 置为 1,其确认号ACK应为 x + 1(ACK 26 501),同时也给出自己的选择序号 y(设置初始段序号SEQ = y ,例如SEQ = 29 010)。
A 收到此报文段后,向 B 给出确认,其确认号应为 y + 1(ACK = 29011)。
衍生问题:
- TCP 为什么是三次握手,而不是两次或四次?
TCP 需要 seq 序列号来做可靠重传或接收,而避免连接复用时无法分辨出 seq 是延迟或者是旧链接的 seq,因此需要三次握手来约定确定双方的 ISN(初始 seq 序列号)。
知乎上有一个特别搞笑的图片,感觉更生动的描述了三次握手的情况:
不过上面的图其实是有点问题的,因为如果第一次握手失败,A其实应该超时重发,而不会发送数据请求,其实理解起来很简单:
A–请求–>B
A<–确认–B
A<–请求–B
A–确认–>B
中间两次可以一起返回,所以是三次
- 为什么HTTP协议要基于TCP来实现?
在Internet中所有的传输都是通过TCP/IP进行的,HTTP协议作为TCP/IP模型中应用层的协议也不例外,TCP是一个端到端的可靠的面向连接的协议,所以HTTP基于传输层TCP协议不用担心数据的传输的各种问题。
- TCP协议工作在哪一层?
OSI七层模型 | TCP/IP概念层模型 | 功能 | TCP/IP协议族 |
---|---|---|---|
应用层 | 应用层 | 文件传输、电子邮件、文件服务、虚拟终端 | TFTP、HTTP、SNMP、FTP、SMTP、DNS、Telnet |
表示层 | 应用层 | 数据格式化、代码转换、数据加密 | 无 |
会话层 | 应用层 | 解除或建立与别的接点的联系 | 无 |
传输层 | 传输层 | 提供端对端的接口 | TCP、UDP |
网络层 | 网络层 | 为数据包选择路由 | IP、ICMP、RIP、OSPF、EGP、IGMP |
数据链路层 | 链路层 | 传输有地址的帧以及错误检测功能 | SLIP、CSLIP、PPP、ARP、RARP、MTU |
物理层 | 链路层 | 以二进制数据形式在物理媒体上传输数据 | ISO2110、IEEE802、IEEE802.2 |
- HTTP3.0为什么选用UDP协议?
来源:https://blog.csdn.net/lunahaijiao/article/details/117267858
因为TCP协议存在以下几个问题:
通信时间较长
RTT(Round-Trip Time),往返时间长,即A->B B->A A-B,需要三次握手,那么相当于一次TCP连接需要1.5RTT
HTTP通信时间,A->B B->A,但是由于TCP第三次握手不需要服务器返回,故这里可以省略0.5RTT
HTTPS通信时间,目前主流浏览器几乎只支持加密的HTTP/2,所以HTTP/2大概率都是HTTPS协议,而HTTPS协议,其实是指HTTP + SSL/TLS,所以需要额外的TLS连接时间,而TLS连接需要4次握手:客户端发送随机数、TLS版本号、支持的密码套件列表给服务器 -> 服务器收到随机数,自己也生成一个随机数,并根据客户端需求的协议和机密方式来发送紫的证书 -> 客户端收到证书并验证有效性,通过后在生成一个随机数,通过服务端证书的公钥加密这个随机数给服务器 -> 服务器收到加密过的随机数并使用私钥解密并获得第三个随机数,然后即可使用这三个随机数来按照之前约定的方式加密生成秘钥,接下来的会话就会使用这个秘钥进行加密解密
所以HTTPS的通信时间总和为: TCP 建立连接时间 + TLS 连接时间 + HTTP交易时间 = 1.5 RTT + 2 RTT + 0.5 RTT = 4 RTT
如果服务器距离客户端较远,一个RTT通常延时在200ms以上,那么光是通信所需耗费的时间就已经接近1s,已经严重影响用户体验了。
- 队头阻塞问题相较于 HTTP/1.1 更严重
因为 HTTP/2 使用了多路复用,一般来说同一域名下只需要使用一个 TCP 连接。当这个连接中出现了丢包的情况,那就会导致 HTTP/2 的表现情况反倒不如 HTTP/1 了。
因为在出现丢包的情况下,整个 TCP 都要开始等待重传,也就导致了后面的所有数据都被阻塞了。但是对于 HTTP/1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
所以,谷歌基于这个问题,对UDP进行了改造,改造的原因如下图:
TCP协议应用广泛,兼容困难,其协议栈又是Linux内部的重要部分,修改和升级成本非常大,所以,谷歌决定在 UDP 基础上改造一个具备 TCP 协议优点的新协议也就顺理成章了,这个新协议就是 QUIC 协议(Quick UDP Internet Connection),并且使用在了 HTTP/3 上,当然 HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。
QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能,比如多路复用、0-RTT、使用 TLS1.3 加密、流量控制、有序交付、重传等等功能。
发起HTTP请求
属于应用层的协议,配合TCP/IP使用
请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。最常的两种GET和POST,如果是RESTful接口的话一般会用到GET、POST、DELETE、PUT。
请求地址:<协议>://<主机>:<端口>/<路径>
常见的Request Header:
1
2
3
4
5
6
7
8
9
10
11Host: www.test.com/ //请求的目标域名和端口号
Origin: http://localhost:8081/ //请求的来源域名和端口号 (跨域请求时,浏览器会自动带上这个头信息)
Referer: https:/localhost:8081/link?query=xxxxx //请求资源的完整URI
User-Agent //浏览器信息
Cookie: //当前域名下的Cookie
Accept: text/html,image/apng //代表客户端希望接受的数据类型是html或者是png图片类型
Accept-Encoding: gzip, deflate //代表客户端能支持gzip和deflate格式的压缩
Accept-Language: zh-CN,zh;q=0.9 //代表客户端可以支持语言zh-CN或者zh(值得一提的是q(0~1)是优先级权重的意思,不写默认为1,这里zh-CN是1,zh是0.9)
Connection: keep-alive //告诉服务器,客户端需要的tcp连接是一个长连接
If-None-Match //如果内容未改变返回304代码,对应Etag
If-Modified-Since //对应last-midified,未被修改则返回304代码常见的Response Header:
1 | Date: //服务端发送资源时的服务器时间 |
常见状态码:
1xx:指示信息–表示请求已接收,继续处理。
2xx:成功–表示请求已被成功接收、理解、接受。
3xx:重定向–要完成请求必须进行更进一步的操作。
4xx:客户端错误–请求有语法错误或请求无法实现。
5xx:服务器端错误–服务器未能实现合法的请求。
浏览器拿到HTML文件
未完待续…