Http 协议简析

Http 协议简析

Http/0.9 是于 1991 年提出,用来网络之间传递 HTML 超文本的内容,所以被称为超文本传输协议

Http/0.9 完整的请求流程

1.Http 是基于 TCP 协议的,客户端要先根据 IP 地址、端口和服务器建立 TCP 连接,而建立连接的过程就是 TCP 协议协议三次握手的过程。
2.建立好连接后,会发送一个 GET 请求行的信息,如GET/index.html 来获取 index.html
3.服务器接受到请求后,读取对应的 HTML 文件,并将数据以 ASCII 字符流返回给客户端。
4.HTML 文档传输完成后,断开连接。

TCP 协议三次握手流程

所谓的三次握手(Three-way HandShake),是指建立一个 TCP 连接时,需要客户端和服务器总共发3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。

1.第一次握手(SYN=1,seq=x)
客户端发送一个 TCP 的 SYN 标志为 1 的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里

2.第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)

服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即 X+1。

3.第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1。

当服务器端接收到第3次握手的包后,TCP握手结束。开始传输数据。

TCP 协议四次挥手流程

TCP 的连接的断开需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作。

1.第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志为 1 的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。

2.第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。

3.第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK

4.第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态

Http/1.0

1.新增请求头字段

1
2
3
4
5
Accept 文件类型
Accept-Encoding 压缩格式
Accept-Charset 字符编码格式
Accept-Language 国际化语音
User-Agent 用于服务器统计客户端信息

2.新增响应头

1
2
Content-Encoding 服务器返回文件的压缩类型
Content-Type 服务器返回的文件类型

3.响应行状态码 Status Code
status code: 200 表示请求成功

4.新增缓存机制,用来缓存已经下载过的资源,减轻了服务端压力

Http/1.1

Http/1.0 发送多个同域名请求。每次请求都需要重新建立 TCP 连接和断开连接的操作,这无疑增加了网络开销,同时也延迟了页面显示

在 Http/1.1 请求头中增加了 Connection 字段,用于提供 TCP 的持久连接。

1
Connection: keep-alive

它默认是开启持久连接的,即对于同一个域名,浏览器默认支持 6 个 TCP 持久连接。建立一次 TCP 连接,可以发送多次 HTTP 请求。

Http/1.1 通过引入 Chunk transfer 机制来支持动态内容:服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。

Http/1.1 还引入了客户端 Cookie 机制和安全机制

Http/2

Http/1.1 尽管作出很多优化,但对带宽的利用率并不理想。
带宽是指每秒最大能发送或者接收的字节数。我们把每秒能发送的最大字节数称为上行带宽,每秒能够接收的最大字节数称为下行带宽。

Http/1.1 很难将带宽用满。主要由3个问题导致:

1.TCP 慢启动
一旦一个 TCP 连接建立之后,就进入了发送数据状态,刚开始 TCP 协议会采用一个非常慢的速度去发送数据,然后慢慢加快发送数据的速度,直到发送数据的速度达到一个理想状态,我们把这个过程称为慢启动。

2.同时开启多条 TCP 连接,这些连接会竞争固定的带宽。

3.HTTP/1.1 队头阻塞的问题
HTTP/1.1 中使用持久连接时,虽然能公用一个 TCP 管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。这意味着我们不能随意在一个管道中发送请求和接收内容。

为了解决 Http/1.1 中的问题,Http/2 采用多路复用的机制。

Http/2 多路复用

浏览器针对同一域名的资源,只建立一个 TCP 连接通道,所有的针对这个域名的请求全部都在这个通道中完成。

数据的传输不再使用文本格式,而是会将它们分割为更小的流和帧,并对他们采用二进制格式的编码。在一个 TCP 连接通道中,支持任意数量的双向数据流,这些数据流是并行、乱序的且它们之间互不干扰。而数据流中传输的数据是二进制帧,它是 Http/2 中数据传输的最小单位,一个流中的帧是按照顺序传输的,且是并行的,所以无需按顺序等待。

Http/2 因为只使用一个 TCP 连接,所以减少了由于 TCP 慢启动而消耗的时间,另外也由于只有单条 TCP 连接,所以不存在不同的 TCP 争夺网络带宽的问题

客户端发送的请求经过二进制分帧层后,不再是一个个完整的 HTTP 请求报文,而是一堆乱序的帧(即不同流的帧是乱的,但是同一条流的帧数顺序传输的),所以就不会按顺序传输,也就不存在等待,从而解决了 HTTP 对头阻塞问题。

Http/2 其他特性

1.可以设置请求的优先级
支持设置请求的优先级,这样服务器收到高优先级的请求后,会优先处理。

2.服务器推送
在 HTTP/2 中服务器解析到一个 HTML 页面后,服务器知道浏览器需要这个页面上引用到的资源,比如 CSS 和 JS,那么服务器就会主动的把这些资源一并推送给浏览器,减少客户端的等待时间。

3.头部压缩
HTTP/2 使用 HPACK 压缩算法对请求头和响应头进行压缩。

Http 缓存

浏览器缓存指的就是浏览器对之前请求过的文件进行缓存,以便在下一次访问时重复使用,从而节省带宽、提升访问速度、降低服务器压力。

HTTP 缓存机制就是利用HTTP响应头将所请求的资源在浏览器中进行缓存,缓存方式主要分为两种:强缓存、协商缓存。

Http 强缓存

强缓存是指在缓存期间不会向服务器发起请求,只有过期后才会想服务器发起请求。

1.Expires

Expireshttp1.0 中的字段,是一个绝对时间,即服务器时间。浏览器检查当前时间,如果还没到失效时间就直接使用缓存文件。

1
<meta http-equiv="Expires" content="0" />

2.Cache-Control

由于 Expires 存在服务器时间与客户端时间不一致的问题,所以 http1.1 中新增了 Cache-Control 字段。
通过设置 max-age 来保存一个相对时间,表示其在该相对时间内容有效。

1
<meta http-equiv="Cache-Control" content="no-cache" />

content 可以设置为:

1
2
3
4
5
6
private: 默认值,表示客户端可以缓存,中间代理、CDN等不能缓存此响应
public: 表示客户端和代理服务器都可缓存
max-age=xxx: 缓存的内容将在xxx秒后失效
no-cache: 需要使用协商缓存来验证缓存数据
no-store: 所有内容都不会缓存(包括协商缓存),每次都向服务器请求最新资源
must-revalidate: 在缓存过期前可以使用,过期后必须向服务器验证

当同时设置 Expires 和 Cache-Control 时,浏览器会优先使用 Cache-Control

Http 协商缓存

协商缓存都会向服务器发送请求,判断缓存数据是否过期,过期的话会返回新的内容,没有过期则使用本地的缓存数据。

1.Last-Modify

Last-modifiedhttp1.0 中的字段,是第一次请求资源时,服务器返回的字段,表示最后一次更新的时间。下一次浏览器请求资源时就发送 if-modified-since 字段。服务器用本地 Last-modified时间与 if-modified-since 时间比较,如果不一致则认为缓存已过期并返回新资源给浏览器;如果时间一致则发送 304 状态码,让浏览器继续使用缓存。

2.Etag

Etaghttp1.1 中新增的字段,是资源的实体标识(哈希字符串),当资源内容更新时,Etag 会改变。服务器会判断 Etag 是否发生变化,如果变化则返回新资源,否则返回304。

参考

一文了解 Http 发展史
http 缓存
TCP 三次握手,四次挥手
Http 强缓存