ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

学习笔记04-2601002-计算机网络学习:HTTP协议版本对比

学习笔记04-2601002-计算机网络学习:HTTP协议版本对比 该文章为ai润色原文笔记在最后。该文章仅为个人记录所写。一、HTTP/1.0 与 HTTP/1.11. 短连接和长连接HTTP/1.0 默认不复用连接一次请求、响应完成后通常就关闭 TCP 连接。HTTP/1.1 默认使用持久连接也就是常说的长连接可以在同一条 TCP 连接上继续发送后续请求。建立 TCP 连接需要握手关闭连接也有开销。每次请求都重新建立连接会重复付出这些成本。长连接可以减少这种重复操作。这里的“长”不代表一直不关闭。服务器可以设置空闲超时双方也可以显式要求关闭连接。HTTP/1.1 中常见的写法是Connection: close长连接也不等于服务器持续向客户端推送数据它首先表示连接可以被后续请求复用。2. HTTP/1.0 的 keep-alive 为什么容易遇到兼容问题一些 HTTP/1.0 实现通过Connection: keep-alive扩展支持持久连接但这不是当时 HTTP/1.0 标准里的统一机制。经过不理解这个扩展的旧代理时可能出现连接处理不一致一方等对方关闭连接来判断响应结束另一方却打算保留连接结果互相等待。HTTP/1.1 对持久连接和逐跳连接管理作了明确规定。不过有代理也不意味着客户端一路连到源站的是同一条连接。客户端到代理、代理到后端各自管理自己的连接。3. Host 头一台服务器可以承载多个站点。如果请求里只有/index.html这样的路径服务器还需要知道请求的是哪个站点。HTTP/1.1 要求请求携带Host例如GET /index.html HTTP/1.1 Host: www.example.com这让服务器或代理能够根据目标主机选择站点也就是基于名称的虚拟主机。HTTP/1.0 并不是完全不能传递主机信息而是没有强制要求Host。4. 消息定界TCP 提供的是字节流不会自动告诉 HTTP“这一条响应到这里结束”。HTTP/1.0 可以用Content-Length表示响应体的字节数。对于有响应体、又没有给出长度的响应关闭连接也可以用来表示结束。但如果想保留连接这个办法就不够用了。HTTP/1.1 引入了分块传输Transfer-Encoding: chunked内容被拆成多个块每个块带有长度最后通过结束块表明传输完成。因此服务端不必先知道整个响应体有多长可以一边生成一边发送。5. 状态码和缓存HTTP/1.1 扩展了状态码和相关语义。例如101 Switching Protocols表示切换协议408 Request Timeout表示服务器没有在愿意等待的时间内收到完整请求。这里的408表达的是等待完整请求超时不能简单归因于长连接的引入。空闲连接超时也可能直接被关闭不一定返回 408。缓存可以先分成两个问题理解新鲜度已缓存的响应是否还可以直接使用再验证需要联系服务器时能否确认内容没变从而避免重新下载完整内容HTTP/1.0 不只有Expires也有Last-Modified和If-Modified-Since。HTTP/1.1 进一步完善了缓存规则包括Cache-Control、ETag、If-None-Match以及共享缓存和私有缓存的控制。例如浏览器可以携带 ETag 进行条件请求。如果资源没有变化服务器可以返回304 Not Modified浏览器继续使用缓存的内容。二、HTTP/2HTTP/1.1 复用了连接但多个请求仍然容易排队。HTTP/2 的主要变化是使用二进制帧组织通信让多个请求、响应能够在同一条 TCP 连接上交错传输。1. Stream、Message 和 Frame名称简单理解Stream流一条逻辑上的通信通道通常承载一次请求、响应交换Message消息一条完整的 HTTP 请求或响应Frame帧HTTP/2 的基本通信单位一条消息可以由多个帧组成不同流的帧可以交错发送帧头中的 Stream ID 用来标识所属流。一些控制帧作用于整个连接使用 Stream ID 0。下面只是传输顺序的示意Stream 1 的 HEADERS Stream 3 的 HEADERS Stream 1 的 DATA Stream 3 的 DATA Stream 1 的 DATA接收端根据帧结构和 Stream ID 分辨这些内容交给对应的流。但这里的“交错”不是“HTTP/2 从 TCP 收到乱序帧再重新排序”。网络包可能乱序TCP 会先恢复字节顺序再把字节流交给 HTTP/2。二进制分帧是 HTTP/2 为多路复用采用的组织方式也不能扩大成“任何文本协议都不可能实现复用”。常见帧包括帧类型主要作用HEADERS传输头部块DATA传输正文数据SETTINGS交换连接参数WINDOW_UPDATE更新流量控制窗口RST_STREAM结束或取消某个流GOAWAY通知连接准备停止接受新的流PUSH_PROMISE宣告服务器准备推送的请求PING检查连接或测量往返情况CONTINUATION继续传输未放完的头部块PRIORITY旧版优先级信令新规范已弃用这套机制2. 多路复用HTTP/1.1 支持流水线可以不等前一个响应完成就发送后续请求但响应仍要按请求顺序返回。前面的响应慢后面的响应就可能被挡住这就是应用层的队头阻塞。HTTP/2 让不同请求使用不同的流响应帧可以交错传输。一个响应暂时没有数据可发其他流仍可以继续发送。3. HPACK减少重复的头部信息很多请求会重复携带Cookie、User-Agent、Accept等字段。HTTP/2 使用 HPACK 压缩头部减少这部分传输开销。HPACK 主要用到静态表、动态表和哈夫曼编码常见字段可以引用预设表项连接中出现过的字段可以引用动态表项字符串也可以进行编码压缩。4. 服务器推送HTTP/2 定义了 Server Push服务端可以在响应一个请求时提前发送它认为客户端还会需要的其他资源。三、HTTP/2 为什么还会被丢包影响HTTP/2 的多路复用建立在 TCP 之上而 TCP 向上提供按序交付的字节流。假设中间缺了一段字节后面的字节即使已经到达TCP 也需要等待缺失部分恢复才能继续按序交付。多个 HTTP/2 流共享这条字节流就可能一起受到影响。所以需要把两种队头阻塞分开记所在层次原因HTTP/2 是否解决HTTP 应用层HTTP/1.1 流水线响应必须按序返回通过多路复用避免这种响应排队TCP 传输层缺失字节使后续字节等待按序交付仍然存在四、HTTP/3HTTP/3 把 HTTP 映射到 QUIC 上QUIC 建立在 UDP 之上。它继续保留 HTTP 的方法、状态码和头部等语义变化主要在通信方式。1. UDP 不可靠QUIC 怎么保证可靠UDP 本身不提供可靠、有序交付也不提供拥塞控制。QUIC 在它之上实现可靠传输、丢包恢复、拥塞控制和流量控制并结合 TLS 1.3 保护通信。所以 HTTP/3 不是直接把 HTTP 数据交给 UDP 后就不管丢包了。HTTP/1.1、HTTP/2 → TCP HTTP/3 → QUIC → UDP2. QUIC 的流为什么能减少互相等待QUIC 为每条流提供有序的数据交付但不要求不同流的数据彼此按同一个顺序交付。某个流缺少数据时这条流仍需要等待恢复其他流已经完整收到的数据可以继续交给应用不必一起等这条流补齐。不过一个丢失的 QUIC 包可能携带多个流的数据这些流都会受到影响。丢包检测与恢复也不是每条流各自独立完成一套机制关键区别在于各流分别按序交付。拥塞控制、连接级流量控制等限制仍可能影响整个连接。HTTP/3 避免了 TCP 那种跨流的按序交付阻塞。3. 流量控制和包大小QUIC 的流量控制分为连接级和流级既限制整个连接允许发送的数据量也限制单条流的数据量。包大小方面可以先记一条明确规则客户端发送的、包含 Initial 包的 UDP 数据报其 UDP 载荷至少要达到 1200 字节必要时填充。这里说的是承载 Initial 包的数据报不是所有 QUIC 包都必须这么大。五、HTTP/3 为什么用 QPACKHTTP/2 使用 HPACKHTTP/3 使用 QPACK。我先把 QPACK 理解成适应 QUIC 多流传输的头部压缩方案而不是简单记成“比 HPACK 更高效”。HPACK 的压缩状态依赖有序处理。QUIC 不保证不同流之间的数据到达顺序如果一个请求的头部引用了还没有收到的动态表项解码就需要等待。QPACK 继续使用静态表、动态表和哈夫曼编码并把动态表相关的指令放到专用的单向流中专用流作用编码器流发送动态表插入等更新指令解码器流回传头部解码确认、插入计数增量、流取消等反馈这样可以更灵活地管理表项依赖。但 QPACK 并不是完全不会阻塞头部引用的表项尚未到达时仍可能等待。协议限制可能阻塞的流数量在压缩效果与等待风险之间作取舍。六、把几个版本放在一起看版本底层传输主要变化需要记住的限制HTTP/1.0TCP默认不持久连接已有基础状态码和缓存机制持久连接依赖扩展的支持与兼容性HTTP/1.1TCP默认持久连接、强制 Host、分块传输、完善缓存流水线响应仍按序返回HTTP/2TCP二进制帧、多路复用、HPACKTCP 层的队头阻塞仍在HTTP/3QUIC / UDP跨流独立交付、QUIC 安全与传输机制、QPACK同一流仍按序交付压缩依赖和连接级限制也可能带来等待原文内容如下原文内容可能有错误仅供参考HTTP协议HTTP/1.0与HTTP/1.1的区别连接方式:HTTP/1.0默认为短连接而HTTP/1.1默认为长连接。都是基于TCP协议的长连接和短连接。TCP协议需要开启三次握手才能建立连接连接中如果丢包会触发重发机制强制等待造成堵塞断开连接需要四次挥手。而长连接是开启三次握手建立连接后进入等待不立马挥手断开只有收到断开指令或者等待超时才挥手断开。为什么HTTP/1.0开启长连接可能会假活HTTP/1.0设计之初没有考虑安全长连接机制也就是说HTTP/1.0的头部Connection: keep-alive是非标准的如果长连接通过中转会产生假活中转服务器接受到Connection: keep-alive开启长连接但是由于是非标准的头部所以中转服务器发送给下一个服务器的连接无法开启长连接连接池被耗尽导致连接假活 ​HTTP/1.1如何解决长连接通过将长连接协议默认开启用Connection: close显式关闭连接默认为长连接并且中转的连接也能保证状态状态码添加了大量状态码新机制产生大量状态码比如长连接空闲超时诞生了408 Request Timeout协议升级诞生了101 Switching Protocols等。状态码是对协议语义的解释而不是为了添加而添加。Host头与虚拟主机HTTP/1.0的请求行里只有路径没有主机名服务端不知道客户端要的是哪个站点。为什么这会导致长连接复用不了一台服务器上跑多个域名时TCP连着也没用因为逻辑上分不清请求属于哪个站点所以一个连接只能服务一个域名。HTTP/1.1强制要求Host头才让“一条连接给多个域名复用”变成可能这也是CDN、反向代理、云原生ingress能成立的前提。消息定界HTTP/1.0的动态内容只能靠关闭连接来标记结束这和长连接直接冲突——要么每次都能算出Content-Length要么就必须断连。HTTP/1.1怎么解决引入了Transfer-Encoding: chunked分块传输长度未知的内容可以一边生成一边发同时严格规定了Content-Length优先、chunked兜底以及HEAD/1xx/204/304这些情况不能有body。这是长连接真正能安全跑起来的底层前提线上常见的“Nginx关掉缓冲后响应被截断”就是这一层出的问题。缓存体系重写HTTP/1.0只有Expires靠时间猜 freshnessHTTP/1.1升级成“新鲜度 再验证”双层模型并区分了共享缓存和私有缓存。HTTP/2的升级HTTP/2最大的升级就是从文本行协议改为了二进制帧协议也就是说可以进行多路复用极大提高了效率二进制分帧层HTTP/1.1 是文本协议一行一行地读HTTP/2 把所有通信拆成更小的单位叫帧Frame在一个 TCP 连接里交错发送。Stream流一个逻辑请求/响应→ Message报文由若干帧组成→ Frame最小传输单位。常见帧类型只有十种HEADERS头部、DATA正文、SETTINGS连接参数协商、WINDOW_UPDATE流量控制、RST_STREAM单流重置、GOAWAY整连接关闭、PUSH_PROMISE推送预告、PING、PRIORITY、CONTINUATION。二进制帧的好处TCP 是字节流、没有消息边界。文本协议里一个请求结束靠空行和Content-Length判断两个请求的字节一旦交错接收端根本分不清哪段属于谁。帧头里塞了一个Stream ID接收端就能把乱序到达的帧按 ID 重新拼回各个 Stream——多路复用在物理上才成立。文本协议永远做不到这点。多路复用MultiplexingHTTP/1.1 一条连接上请求必须串行前一个响应没收完后一个请求就得排队。浏览器的妥协是给同一域名开 6 个 TCP 连接。HTTP/2 之后一条 TCP 连接开几十上百个 Stream帧交错发送、乱序到达、按 ID 重组。Stream 之间还带优先级依赖树 权重HTML 里关键 CSS 可以排在图片前面。所以HTTP/2在处理多个请求时更加高效并且减少了网络延迟提高了性能HPACK 头部压缩。HTTP/1.1 每个请求都要重发几乎一模一样的头Cookie、User-Agent、Accept、Accept-Encoding、Accept-Language……动辄几百到几千字节而且明文不压缩。一个页面几十个请求头部开销能超过正文本身。而HTTP/2支持对Header头部进行压缩并且为Header头部压缩设置了专门的HPACK 算法。服务器推送(Server Push。HTTP/2可以通过服务器推送让客户端在请求一个资源时顺手把其他资源也一并推送客户端节省了解析 HTML → 发现资源 → 再发请求这一整个 RTT。HPPT/3的升级HTTP/1HTTP/2都是基于TCP的连接而HTTP/3则是替换为QUIC。而QUIC是构建于UDP之上在传输层实现可靠交付、拥塞控制、流量控制和 TLS 1.3 安全保护。为什么必须抛弃 TCP归根结底TCP 是字节流协议向上层承诺字节严格按序、无丢失、无重复。应用层拿到的是必须是按照顺序的包只要中间丢一个包内核必须等重传补齐才能把后面的字节交出来这就会造成堵塞这是TCP无法避免的所以就只有把目光放在UDP上。为什么 HTTP/2 的多路复用反而放大了这个问题HTTP/1.1 开 6 条 TCP 连接一条堵了另外五条照跑。HTTP/2 把几十个 Stream 全塞进一条TCP 连接所有帧共用同一条字节流——任意一个包丢失这条连接上所有 Stream 一起冻结。请求越并发单个丢包的伤害面越大。弱网高丢包场景下 HTTP/2 实测输给 HTTP/1.1 多连接。如何解决UDP的不可靠性UDP 只提供端口复用和校验和不保证可靠、不保证有序、不拥塞控制。QUIC 在这之上自己实现了整套机制关键点是流Stream成为可靠传输的单位而不是整条连接每条 Stream 独立做丢包恢复。一个包丢了只有它承载的那些 Stream 的帧需要重传其他 Stream 的帧即使在后续包里也能立刻交给应用层。这是彻底解决队头阻塞的核心HTTP/3 全部的延迟收益都来自这一句。流量控制分两级。连接级 每个 Stream 级和 HTTP/2 的双层窗口思路一致但这次是在传输层原生的。强制 PMTUD。QUIC 自己做路径 MTU 发现客户端 Initial 包必须填充到至少 1200 字节。头部压缩HTTP/2.0 使用 HPACK 算法进行头部压缩而 HTTP/3.0 使用更高效的 QPACK 头压缩算法。HPACK 的动态表要求两端严格按序更新。但 QUIC 的 Stream 是独立且乱序的。如果沿用 HPACK一个 Stream 的 HEADERS 帧引用了还没到达的动态表条目这个 Stream 就必须停下来等就会导致队头阻塞被头部压缩机制原封不动地搬回了应用层。而QPACK保留 HPACK 的静态表 动态表 哈夫曼编码三件套但把表的同步从请求流里剥离出来放到两条专用的单向流unidirectional stream上QPACK 编码器流专门发送动态表的插入更新QPACK 解码器流回传 Insert Count 确认告诉对端我已经收到多少条表项了。
返回列表