在浏览器中输入URL并按回车之后会发生什么
1. 输入URL并解析
输入URL后,浏览器会解析出协议、主机、端口、路径等信息,并构造一个HTTP请求(浏览器会根据请求头判断是否又HTTP缓存,并根据是否有缓存决定从服务器获取资源还是使用缓存资源)
2. DNS域名解析,将域名解析成对应的IP地址
DNS是一种用于将域名(www.baidu.com)转换成IP地址(220.181.111.188)的分布式系统。
3. 建立TCP三次握手
4. 浏览器发送HTTP/HTTPS请求到web服务器
5. 服务器处理HTTP请求并返回HTTP报文
服务器会接受请求并将其传递给请求处理程序并发送HTTP响应,一般响应报文包含:请求网页以及状态码,压缩类型,如何缓存的页面,设置cookie;
6. 浏览器渲染页面
7. TCP四次挥手断开连接
HTTP版本演变
HTTP/1.0
是HTTP协议的第一个正式版本,主要有以下特性:
- 引入了请求头和响应头,支持多种请求方法和状态码
- 不支持持久连接,每次请求都需要建立新的连接
HTTP/1.1
- 长连接
为了解决HTTP/1.0每次请求都需要建立新的连接的问题,HTTP/1.1提出了长连接(持久连接),只要客户端和服务器任意一端没有明确提出断开连接,则保持TCP连接状态
2. 管道网络传输
在同一个TCP连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发送第二个请求,可以减少整体的响应时间。
客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等服务器做出回应,收到后再发出B请求。那么,管道机制则是允许浏览器同时发出A请求和B请求。
但是服务器必须按照接受请求的顺序发送对这些管道化请求的响应。
如果服务端在处理A请求时耗时比较长,那么后续的请求的处理都会被阻塞,这称为队头阻塞
HTTP/1.1管道解决了请求的对头阻塞,但没有解决响应的对头阻塞。
3.对头阻塞
当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一值请求不到数据,。
但是HTTP/1.1仍然存在很多问题:
- 头部冗余:每个请求你和响应都需要带有一定的头部信息,每次互相发送相同的头部造成的浪费较多;
- 服务器是按请求的顺序相应的,如果服务器响应慢,会导致客户端一直请求不到数据,也就是队头阻塞;
- 没有请求优先级控制
- 请求只能从客户端开始,服务器只能被动响应
HTTP/2
HTTP/2 协议是基于HTTPS的,所以HTTP/2的安全性也是有保障的
- 头部压缩:HTTP/2使用了HPACK压缩算法对请求头和响应头部进行压缩,减少了传输的头部数据量,降低了延迟
- 二进制帧:HTTP/2将数据分割成二进制帧进行传输,分为头信息帧和数据信息帧,增加了数据传输的效率
- 并发传输:引出Stream概念,多个Stream复用在一条TCP连接,针对不同的HTTP请求用独一无二的Stream ID来区分,接收端可以通过Stream ID 有序组装成HTTP消息,不同Stream的帧可以乱序重发送的,因此可以并发不同的Stream,也就是HTTP/2可以并行交错地发送请求和响应
- 服务器推送:在HTTP/2中,服务器可以对客户端的一个请求发送多个响应,即服务器可以额外的向客户端推送资源,而无需客户端明确的请求
但是HTTP/2仍然存在队头阻塞的问题,只不过在传输层
HTTP/2是基于TCP协议来传输数据的,TCP是字节流协议,TCP层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给HTTP应用,那么【当前1个字节数据】没有到达时,后收到的字节数据只能存放在内核缓冲区中,只有等到者1个字节的数据到达时,HTTP/2应用层才能从内核中拿数据,这就是HTTP/2的队头阻塞问题。
并发实现:
先来理解三个概念:Stream、Messager、frame
从图中可以看出
- 一个TCP连接包含一个或多个Stream,Stream时HTTP/2并发的关键技术
- Stream包含1个或多个Message,Message对应HTTP/1中的请求或响应,由HTTP头部和包体构成
- Message里面包含一条或多条frame,frame时HTTP/2最小单位,以二进制压缩格式存放HTTP/1中的内容
HTTP 消息可以由多个 Frame 构成
一个 Frame 可以由多个 TCP 报文构成
在 HTTP2 连接上,不同 Stream 的帧可以乱序发送(因此可以并发不同的 Stream),接收端可以通过 Stream ID 有序组装 HTTP 消息。
HTTP/2 通过 Stream 实现的并发,比 HTTP/1.1 通过 TCP 连接实现并发要牛逼的多,因为当 HTTP/2 实现 100 个并发 Stream 时,只需要建立一次 TCP 连接,而 HTTP/1.1 需要建立 100 个 TCP 连接,每个 TCP 连接都要经过 TCP 握手、慢启动以及 TLS 握手过程,这些都是很耗时的。
HTTP/2 还可以对每个 Stream 设置不同优先级,帧头中的「标志位」可以设置优先级,比如客户端访问 HTML/CSS 和图片资源时,希望服务器先传递 HTML/CSS,再传图片,那么就可以通过设置 Stream 的优先级来实现,以此提高用户体验。
HTTP/3
HTTP/3 基于 QUIC 协议,具有以下特点:
- 零 RTT 连接建立:QUIC 允许在首次连接时进行零往返时间(Zero Round Trip Time)连接建立,从而减少了连接延迟,加快了页面加载速度。
- 无队头阻塞:QUIC 使用 UDP 协议来传输数据。一个连接上的多个 stream 之间没有依赖,如果一个 stream 丢了一个 UDP 包,不会影响后面的 stream,不存在 TCP 队头阻塞
- 连接迁移:QUIC 允许在网络切换(如从 Wi - Fi 到移动网络)时,将连接迁移到新的 IP 地址,从而减少连接的中断时间。
- 向前纠错机制:每个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。向前纠错牺牲了每个数据包可以发送数据的上限,但是减少了因为丢包导致的数据重传。
HTTP 缓存
将资源(如网页、图像、脚本等)的副本存储在客户端或中间代理服务器上,以便将来的请求可以直接从缓存中获取,而不必重新从服务器下载资源。这有助于减少网络延迟,提高页面加载速度,并减轻服务器的负担。
缓存可以解决什么问题
- 减少不必要的网络传输,节约带宽
- 更快的加载页面
- 减少服务器负载,避免服务过载的情况出现
强制缓存
强缓存:浏览器判断请求的目标资源是否有效命中强缓存,如果命中,则可以直接从内存中读取目标资源,无需与服务器做任何通讯。
Expires 强缓存:设置一个强缓存时间,此时间范围内,从内存中读取缓存并返回。
Cache-Control 强缓存:http1.1 中增加该字段,使用 max-age 指令,可以设置资源在缓存中的最长有效时间,单位为秒。例如,Cache-Control: max-age=3600 表示资源在缓存中保留 3600 秒
协商缓存
与强制缓存不同,协商缓存依赖于客户端和服务器之间的交互,在协商缓存中,服务器在响应中提供了资源的一些标识信息,客户端在后续请求中通过这些信息来判断资源是否发生了变化,进而判断是否需要重新传输资源。
下面是常用于协商缓存的一些头部字段
ETag 和 If-None-Match:
- ETag 是服务器为资源生成的唯一标识符,可以是根据文件内容计算出的哈希值。
- 客户端在请求头部的 If-None-Match 字段中携带上次响应的 ETag 值。
- 服务器比较请求中的 If-None-Match 值与当前资源的 ETag 值,如果匹配,表示资源未发生变化,返回状态码 304 Not Modified。
Last-Modified 和 If-Modified-Since:
Last-Modified 是资源的最后修改时间,服务器在响应头部中返回。
客户端在请求头部的 If-Modified-Since 字段中携带上次响应的 Last-Modified 时间。
服务器比较请求中的 If-Modified-Since 值与当前资源的 Last-Modified 值,如果请求时间早于资源的最后修改时间,表示资源未发生变化,返回状态码 304 Not Modified。