HTTP 协议是什么
HTTP (Hypertext Transfer Protocol) 是一种应用层协议,用于在计算机网络中传输超文本文档。HTTP 协议是 Web 上的基础协议,用于在客户端和服务器之间传输数据。
HTTP 协议的工作原理是客户端发送一个请求到服务器,服务器接收请求后处理请求,并返回一个响应给客户端。HTTP 请求包含请求行、请求头和请求体,而 HTTP 响应包含响应行、响应头和响应体。
HTTP 协议使用 TCP (Transmission Control Protocol) 协议作为其传输层协议,因此它是可靠的协议,可以保证数据的完整性和可靠性。
HTTP 协议有多个版本,其中最常见的是 HTTP/1.1 和 HTTP/2。HTTP/1.1 是早期的版本,HTTP/2 是较新的版本,引入了一些新的特性,例如多路复用、服务器推送等,可以提高网站性能和速度。
HTTP/1.1
HTTP 1.1 的特点是什么
HTTP/1.1 是 HTTP 协议的一个版本,相对于早期的 HTTP/1.0 版本,它引入了一些新的特点和改进,包括:
持久连接(Persistent Connections):HTTP/1.1 默认启用了持久连接,即客户端与服务器之间可以重复使用同一个连接来传输多个请求和响应,减少了连接建立和关闭的开销,提高了传输效率。
管道化(Pipeline):HTTP/1.1 支持管道化,即在一个持久连接中,客户端可以同时发送多个请求,服务器也可以同时返回多个响应,这样可以进一步提高传输效率。
增量传输编码(Incremental Transfer Encoding):HTTP/1.1 引入了增量传输编码,可以将响应体分成多个部分,随着传输逐步返回给客户端,这对于传输大文件或流媒体数据非常有用。
1
2
3
4
5
6
7
8
9200 OK
Content-Encoding: gzip
Transfer-Encoding: chunked
25
This is the first part of the response.
1F; name=value
And this is the second part of the response, with some metadata.
0在上面的响应报文中,Content-Encoding 头指定了响应使用了 gzip 压缩算法进行压缩,Transfer-Encoding 头指定了使用了 chunked 编码进行传输。响应报文的主体被分成了两个 chunk,第一个 chunk 大小为 0x25(即 37 字节),包含了响应的一部分内容;第二个 chunk 大小为 0x1F(即 31 字节),包含了响应的另一部分内容,同时还带有一个名为 name 的元数据,其值为 value。注意,最后的 chunk 大小为 0,表示这是最后一个 chunk。
客户端接收到这个响应后,可以立即开始处理第一个 chunk 中的内容,而不需要等待整个响应全部生成后再开始处理。当响应生成的过程中,有更多的数据可以发送给客户端时,服务器会把这些数据添加到响应中的下一个 chunk 中,直到响应生成完毕。这样可以显著减少客户端等待响应的时间,提高用户体验。支持范围请求(Range Requests):HTTP/1.1 支持客户端发送范围请求,即请求只返回指定的数据范围,这对于大文件的下载和断点续传非常有用。
例如这是一个请求一个资源 0-499 bytes 的数据1
2
3GET /path/to/resource
Host: example.com
Range: bytes=0-499服务端对此进行响应
1
2
3
4
5
6206 Partial Content
Content-Type: application/octet-stream
Content-Length: 500
Content-Range: bytes 0-499/1000
<bytes 0-499 of the resource>增加了缓存控制机制:HTTP/1.1 引入了缓存控制机制,可以控制缓存的行为,例如缓存过期时间、是否可缓存、缓存验证等。
以下列举了一些常见的缓存响应头1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Cache-Control: max-age=3600
# 该响应头指示客户端可以缓存该资源,并在 3600 秒内使用缓存副本,而不必重新获取该资源。
Cache-Control: no-cache
# 该响应头指示客户端可以缓存该资源,但在使用缓存副本之前必须先确认其有效性,即向服务器发送一个条件请求来检查资源是否已经更改。如果资源已经更改,则服务器会返回一个新的副本,否则服务器会返回 304 Not Modified 响应,表示缓存副本仍然有效。
Cache-Control: no-store
# 该响应头指示客户端不应该缓存该资源,也不应该将其保存到任何持久性存储中,例如磁盘上的文件或浏览器缓存。
ETag: "abc123"
# 该响应头包含一个唯一的标识符,表示资源的当前版本。客户端可以在后续请求中使用 If-None-Match 头将该标识符发送回服务器,以检查资源是否已更改。
Last-Modified: Sat, 01 Jan 2000 00:00:00 GMT
# 该响应头包含资源的最后修改时间。客户端可以在后续请求中使用 If-Modified-Since 头将该时间戳发送回服务器,以检查资源是否已更改。
If-None-Match: "abc123"
# 该请求头将先前获得的 ETag 值发送回服务器,以检查资源是否已更改。如果资源的 ETag 值与发送的值相同,则服务器会返回 304 Not Modified 响应,表示缓存副本仍然有效。
If-Modified-Since: Sat, 01 Jan 2000 00:00:00 GMT
# 该请求头将先前获得的 Last-Modified 值发送回服务器,以检查资源是否已更改。如果资源的 Last-Modified 值与发送的值相同,则服务器会返回 304 Not Modified 响应,表示缓存副本仍然有效。HTTP/1.1 相比 HTTP/1.0 引入了更多的请求和响应头:例如 Host 头、Connection 头、Keep-Alive 头等,增强了协议的灵活性和可扩展性。
总的来说,HTTP/1.1 是一个相对成熟和稳定的版本,具有较好的兼容性和可靠性,但随着网络应用的不断发展和提升,其性能和效率方面存在一些瓶颈,因此后来引入了 HTTP/2 协议来进一步提升性能和效率。
HTTP 1.1 的缺点
虽然 HTTP/1.1 在协议设计中引入了许多改进和特性,但是也存在一些缺点,包括:
阻塞问题:HTTP/1.1 仍然使用了串行请求和响应的方式,也就是说,每个请求必须等待前面的请求完成后才能继续执行,这样就会导致后面的请求被阻塞, 虽然引进的管道化, 能够同时发送多个请求,服务器也可以同时返回多个响应,但是由于 HTTP/1.1 仍然使用了串行请求和响应的方式,每个请求必须等待前面的请求完成后才能继续执行,因此仍然会存在阻塞的问题。
例如,如果一个客户端同时发送了多个请求到同一个服务器,而这些请求的响应时间不同,那么在串行执行的情况下,如果前面的请求耗时较长,那么后面的请求必须等待前面的请求完成后才能继续执行,这样就会导致后面的请求被阻塞。
虽然管道化可以减少一些连接建立和关闭的开销,但是它并不能完全解决 HTTP/1.1 阻塞的问题。因此,后来的 HTTP/2 协议引入了多路复用和二进制分帧等特性,可以更好地解决阻塞的问题,提高传输效率。高延迟:虽然 HTTP/1.1 支持持久连接,但是在实际应用中,由于各种原因,如网络拥塞、请求频率过高、服务器资源不足等,仍然会出现需要创建新连接的情况。另外,HTTP/1.1 的持久连接虽然减少了连接建立和关闭的开销,但是仍然需要占用服务器的资源,包括 TCP 连接、内存和 CPU 等。当服务器资源不足时,为了保证服务的稳定性和可靠性,可能需要限制连接数量,从而导致需要创建新连接的情况。
安全性问题:HTTP/1.1 的数据传输是明文的,容易被中间人攻击者截获并窃取数据。协议没有对数据进行加密和完整性验证,容易受到各种攻击,例如中间人攻击、跨站脚本攻击、跨站请求伪造等。
性能瓶颈:HTTP/1.1 协议在性能方面存在一些瓶颈,例如头部压缩不足、TCP 连接数量限制等,限制了传输效率和速度。
HTTP/2
HTTP/2 是 HTTP 协议的一种新版本,于 2015 年正式发布。它在 HTTP/1.1 的基础上进行了一系列的改进,旨在提高网络传输的性能和效率,更好地适应现代 Web 应用的需求。主要有以下的特点:
- 多路复用:HTTP/2 可以在同一连接上同时发送多个请求和响应,而不必按照先后顺序依次发送,从而提高了网络吞吐量。
- 二进制分帧:HTTP/2 通过将所有请求和响应分割为二进制格式的帧,从而避免了 HTTP/1.x 中的”队头阻塞”问题。
- 头部压缩:HTTP/2 使用 HPACK 压缩算法对请求和响应的头部进行压缩,从而减少了网络传输的开销。
- 服务器推送:HTTP/2 支持服务器推送,服务器可以在客户端请求之前主动向客户端发送资源,从而减少了客户端的请求次数和网络传输的延迟。
- 优先级设置:HTTP/2 支持设置请求的优先级,可以让客户端告诉服务器哪些请求更重要,从而更好地利用网络资源。
HTTP/2 中的帧
HTTP/2通信使用帧(frame)的方式,相当于将HTTP/1.1中报文的首部和实体拆分成了帧. 每个帧包含了HTTP/2通信的最小单元,由帧头(Frame Header)和帧负载(Frame Payload)两部分组成。
1 | +-----------------------------------------------+ |
帧头(Frame Header)共9个字节, 对于每种类型的帧都是固定的,用于描述帧的基本信息:
- 长度(Length):一个24位的无符号整数,表示帧负载的长度,不包括帧头的9个字节。
- 类型(Type):一个8位的无符号整数,表示帧的类型,例如数据帧、头部帧、优先级帧等。
- 标志(Flags):一个8位的无符号整数,表示帧的一些特性,例如数据帧的结束流(END_STREAM)标志、头部帧的结束头(END_HEADERS)标志等。
- 保留位(Reserved):一个1位的保留字段,必须为0,保留位将在将来的HTTP/2版本中使用。
- 流标识符(Stream Identifier):一个31位的无符号整数,表示该帧所属的流的标识符,用于将帧关联到特定的请求或响应。这使得帧无需按照顺序到达客户端或者服务端.
以下的帧头字段根据传输不同类型的帧指定:
- 附加的流标识符(Associated Stream Identifier):一个31位的无符号整数,表示该帧关联的另一个流的标识符,用于表示该帧与其他流之间的依赖关系。
- 优先级(Priority):一个8位的无符号整数,表示该帧所属流的优先级信息。
- 填充(Padding):一个8位的无符号整数,表示填充(padding)的长度,用于在帧负载的末尾添加附加数据。
- 随机数(Reserved for Exclusive Use by HPACK):一个32位的随机数,用于协议扩展。
- 帧负载(Frame Payload)是帧的实际内容,它的格式和内容根据帧的类型而定。例如,数据帧的负载就是待传输的数据,头部帧的负载就是HTTP头部字段等。帧负载的长度由帧头中的长度字段指定。
HTTP/2 通信过程
HTTP/2的通信过程可以简单概括为以下几个步骤:
- 建立连接:客户端使用TLS协议与服务器建立加密连接,并发送HTTP/2连接前言,包含了一些基本信息,如协议版本、初始流的ID等。
- 发送设置帧:在连接建立后,客户端和服务器都会发送一些设置(SETTINGS)帧,包含了一些连接和流的配置信息,如最大帧大小、最大并发流数等。
- 发送请求:客户端通过一个或多个流(Stream)向服务器发送请求(Request)帧,包含了请求头和请求体。服务器收到请求后,会发送响应(Response)帧,包含了响应头和响应体。
- 处理流:客户端和服务器都可以同时处理多个流。每个流都有一个唯一的标识符(Stream ID),用于标识该流的请求和响应。客户端和服务器可以根据需要创建、关闭和重置流。
- 处理帧:HTTP/2将消息分割成一或多个帧(Frame)进行传输。客户端和服务器都可以同时发送和接收多个帧,每个帧都包含了帧头和帧体。帧头中包含了帧的类型、长度、标识符和其他一些控制信息,帧体中包含了具体的数据。
- 进行流控制:由于HTTP/2中使用了多路复用,因此需要进行流控制,以确保每个流都能够公平地使用带宽。HTTP/2使用了基于窗口的流量控制机制,客户端和服务器都可以通过发送窗口更新(WINDOW_UPDATE)帧来通知对方可以发送的数据量。
- 处理优先级:HTTP/2支持请求的优先级机制,通过为每个流分配一个优先级权重,可以控制带宽的分配。客户端和服务器可以通过发送优先级(PRIORITY)帧来设置流的优先级。
- 使用头部压缩:HTTP/2引入了HPACK头部压缩算法,可以有效减少传输的头部大小。客户端和服务器都可以使用HPACK算法对请求和响应的头部进行压缩和解压缩。
- 关闭连接:HTTP/2使用了长连接,在通信结束后,可以通过发送GOAWAY帧来通知对方关闭连接。服务器和客户端都可以发送GOAWAY帧。
HTTP/2 的缺点
虽然 HTTP/2 在性能方面有很多优点,但也存在一些缺点。以下是几个常见的缺点:
- 首字节延迟问题:由于 HTTP/2 的多路复用和流控制机制,当某个请求或响应需要等待其他流的数据时,它的首字节的延迟可能会很高。这种情况下,使用 HTTP/1.1 的长连接可能更加高效。
- 依赖于 SSL/TLS:HTTP/2 规范要求使用 SSL/TLS 协议进行加密传输,因此使用 HTTP/2 需要在服务器上部署 SSL/TLS 证书。这对于某些小型网站来说可能会增加部署和维护成本。
- 兼容性问题:HTTP/2 是较新的协议,不是所有的浏览器和服务器都支持它。在 HTTP/2 完全普及之前,需要考虑向后兼容性和平滑升级的问题。
- 多个域名问题:HTTP/2 中使用多路复用的机制将多个请求打包在一个 TCP 连接中,这样可以减少建立连接的次数和网络带宽的浪费。但是,由于同一个 TCP 连接只能使用一个证书,如果要在同一个站点上使用多个域名,需要使用 SNI(Server Name Indication)技术,在某些情况下可能会存在兼容性问题。
- 压缩算法的安全性问题:HTTP/2 中使用的 HPACK 算法对 HTTP 报文进行压缩,这虽然可以减少网络传输的数据量,但也可能会导致安全问题。例如,如果攻击者能够篡改压缩的 HTTP 报文,就可能会导致注入攻击或者中间人攻击。
- 调试过程中的困难增加: 由于 HTTP/2 的多路复用和头部压缩,单个请求和响应可能被分成多个帧,在网络分析工具中难以分辨。这使得手动调试 HTTP/2 应用程序变得困难。
- 服务器端推送的性能问题:虽然服务器推送可以在一定程度上提高性能,但是如果使用不当,反而可能会导致性能问题。例如,服务器可能会推送不必要的资源,或者推送资源的优先级过低。
然而,恶意攻击者可以利用这个功能进行非对称 DDos 攻击。攻击者可以构造一些请求触发服务器进行推送大量资源,而这些资源可能是无用的或者是不存在的,从而消耗服务器的资源。而客户端可能无法快速处理所有的推送资源,导致客户端资源耗尽,从而无法处理正常的请求。
为了防止这种攻击,HTTP/2 规范中规定了一些措施,比如服务器应该限制推送的资源数量和大小,客户端可以使用 SETTINGS_MAX_CONCURRENT_STREAMS 设置客户端最大同时接收的流的数量等。同时,应用程序开发者也可以采用一些措施,如限制推送资源的大小和数量,或者在应用层进行流量控制等。 - 队头阻塞: 虽然HTTP/2 使用了多路复用避免了HTTP/1.1 的串行阻塞问题. 但由于 HTTP/2 中采用的 TCP 连接无法将数据拆分成更小的块来传输,所以当连接中的某一部分数据丢失时,后续的所有数据都必须等待此数据重传,导致了队头阻塞问题。此外,HTTP/2 中的流(stream)是基于 TCP 连接上的虚拟通道,每个流都会占用一些连接的资源,如果某些流发生阻塞,会影响到其他流的处理。
HPACK
HTTP/2 使用了 HPACK(HTTP/2 Protocol for Algorithmic Compression of HTTP Headers) 算法来压缩请求和响应头部数据,从而减少数据传输量,降低延迟。HPACK 是一种基于哈夫曼编码的压缩算法,它会对相同的头部名称和值进行编码,并通过索引表来减少重复数据的传输。
HPACK 压缩算法使用两种表格来减少重复的数据:静态表格和动态表格。静态表格是预定义的一张表格,包含了一些常见的头部字段,比如:请求方法、状态码等。动态表格是可以根据请求和响应动态改变的表格,用来存储一些频繁出现的头部字段。
HPACK 算法的压缩过程如下:
- 首先,将头部字段划分为静态头部和动态头部。
- 对于每个头部字段,根据它是否在静态表格或动态表格中进行编码。
- 如果头部字段在静态表格中,编码器会将静态表格中的索引作为编码结果。
- 如果头部字段在动态表格中,编码器会先将表格中的索引作为编码结果,再将值进行哈夫曼编码。
- 如果头部字段不在静态表格或动态表格中,编码器会将字段名称和值进行哈夫曼编码。
在通信过程中,客户端和服务器会共享一张索引表,这张表中包含了之前传输的头部字段信息。客户端可以通过发送一个更新的索引表来通知服务器更新表格。同时,客户端和服务器也可以通过使用首部块分解技术来将头部字段分割成更小的部分,以便于进行并行传输。
虽然 HPACK 算法可以有效地减少传输数据量,但是它也存在一些安全问题。由于 HPACK 使用了哈夫曼编码来压缩头部字段,攻击者可以通过构造恶意的哈夫曼编码来导致解压缩算法出现错误,从而引发安全问题。因此,在实现 HPACK 算法时,需要对哈夫曼编码进行安全性处理。
HTTP/3(QUIC)
HTTP/3 是基于 QUIC 协议的新一代 HTTP 协议,相较于 HTTP/2,它的主要特点包括:
- 基于 QUIC 协议:HTTP/3 是基于 QUIC 协议实现的,这使得它能够继承 QUIC 协议的优点,比如更快的连接建立、更好的拥塞控制和更可靠的传输机制等。
- 解决队头阻塞问题:HTTP/3 使用 QUIC 的多路复用和分组机制,可以避免 HTTP/2 中的队头阻塞问题,从而提高了并发性和吞吐量。
- 强制加密:HTTP/3 强制使用 TLS 1.3 加密,这有助于提高数据的安全性。
- 前向错误纠正(Forward Error Correction,FEC):HTTP/3 引入了 FEC 技术,可以在一定程度上减少数据包丢失对传输质量的影响。
- 无序数据流:HTTP/3 中的数据流是无序的,这意味着即使一个数据包丢失,其他数据包也可以按顺序传输。
- 可插拔的加密算法:HTTP/3 允许使用插件式的加密算法,这使得它更加灵活和可扩展。
HTTP/3 主要的特点是基于 QUIC 协议的实现、缓解队头阻塞问题、强制加密、引入了前向错误纠正和无序数据流等。这些特点都有助于提高 HTTP 协议的性能、安全性和可靠性。
不过QUIC 也不是完全解决了队头阻塞的问题, TCP 出现阻塞的原因是因为所有的流使用同一个滑动窗口, 而QUIC对每一个流使用单独的窗口.
QUIC: A UDP-Based Secure and Reliable Transport for HTTP/2
QUIC: A UDP-Based Multiplexed and Secure Transport
QUIC 协议的概念设计和协议规范-zh
30张图解: TCP 重传、滑动窗口、流量控制、拥塞控制发愁