把 HTTP 讲清楚

你可能遇到过这些情况:

  • 页面第一次打开很慢,第二次秒开
  • 明明改了静态资源,用户却一直看到旧内容
  • 接口偶发慢,抓日志发现后端处理时间并不长
  • 同一个域名,为什么有时是 HTTP/1.1,有时变成了 HTTP/2

这些问题本质都离不开 3 件事:

  • HTTP 报文到底长什么样(你抓包才看得懂)
  • 连接怎么复用(Keep-Alive/HTTP2 多路复用)
  • 缓存怎么生效(强缓存/协商缓存)

我这篇就用"知识分享 + 可验证"的方式,把 HTTP 拆开讲清楚。

目录(按实战排查顺序)

    1. 先把 HTTP 的边界说清楚(它解决什么,不解决什么)
    1. 报文结构:抓包时你到底在看什么
    1. GET vs POST:别背八股,用语义就够了
    1. 版本演进:1.0/1.1/2.0 分别解决了什么痛点
    1. 连接复用:Keep-Alive 到底省了什么
    1. 缓存机制:为什么"第二次秒开",以及怎么让它立刻更新
    1. 实战:用 DevTools/curl 验证与排障
    1. 最后总结

1. 先把 HTTP 的边界说清楚

  • HTTP 是一种 应用层协议,规定客户端与服务端如何用"请求-响应"的方式交换数据。
  • 经典场景:浏览器请求页面、App 请求接口。

你在项目里更常用的表达是:

  • HTTP 是无状态的:协议层不保存会话状态
  • 状态靠应用层补:Cookie/Session/Token

2. 报文结构:抓包时你到底在看什么

2.1 请求报文(Request)

  • 请求行:METHOD path HTTP/version
  • 请求头:Header: value
  • 空行
  • 请求体(可选)

2.2 响应报文(Response)

实战里你重点看三类东西:

  • 状态码:成功/重定向/缓存/失败

  • 关键响应头:缓存相关、内容类型、压缩相关

  • 响应体大小与耗时:到底慢在网络还是慢在后端

  • 状态行:HTTP/version status_code reason

  • 响应头

  • 空行

  • 响应体


3. GET vs POST:别背八股,用语义就够了

你可以这样讲:

  • 语义:GET 用于获取资源;POST 用于提交数据/产生副作用。
  • 幂等性:GET 通常幂等;POST 通常不幂等。
  • 参数位置:GET 常放在 URL query;POST 常放在 body(但不是强制)。

容易踩坑的一句话:

  • 不是"GET 不能有 body",而是多数实现不使用/不转发。

4. 版本演进:1.0/1.1/2.0 分别解决了什么痛点

4.1 HTTP/1.0:一次请求一次连接

  • 默认短连接:一次请求一次连接
  • 性能问题:连接建立/释放开销大

4.2 HTTP/1.1:默认 Keep-Alive,开始"复用连接"

核心改进:

  • 默认持久连接(Keep-Alive):减少重复握手
  • 管线化(Pipelining):理论上可连续发送请求,但实践中受限
  • 缓存机制更完善 :Cache-Control、ETag 等

但它仍有一个很要命的瓶颈:

  • 队头阻塞(Head-of-Line Blocking):同一连接内,前一个请求没返回,后面的可能被阻塞。

4.3 HTTP/2:一个连接里并发多个请求(多路复用)

核心改进(背诵版):

  • 二进制分帧:不再是纯文本行
  • 多路复用:一个连接并发处理多个 stream
  • 头部压缩:HPACK
  • 服务端推送:Server Push(实际使用需谨慎)

工程里你要记住一句:

  • HTTP/2 解决了应用层的队头阻塞,但底层仍基于 TCP,TCP 层仍可能队头阻塞。

5. 连接复用:Keep-Alive 到底省了什么

Keep-Alive 的意义:

  • 复用同一个 TCP 连接承载多个 HTTP 请求
  • 减少三次握手/慢启动开销

但要注意两个现实问题:

  • 连接复用不是无限的,服务端通常有连接数、超时时间等限制

6. 缓存机制:为什么"第二次秒开",以及怎么让它立刻更新

你排查缓存问题时,也建议按"先强后协商"来判断。

6.1 强缓存

特点:

  • 不发请求到服务端
  • 浏览器直接用本地缓存

常见头:

  • Cache-Control: max-age=...
  • Expires

6.2 协商缓存

特点:

  • 会发请求到服务端
  • 服务端告诉你"缓存是否还可用"

常见头:

  • If-None-Match / ETag
  • If-Modified-Since / Last-Modified

协商缓存命中时通常返回:

  • 304 Not Modified

7. 实战:用 DevTools/curl 验证与排障

7.1 用浏览器 DevTools 看协议版本/连接复用

  • 打开 Chrome DevTools -> Network
  • 勾选 Disable cache(排查缓存时很有用)
  • 看 Protocol 列(h2 表示 HTTP/2)
  • 看 Connection ID/Remote Address(不同版本浏览器字段略有差异),判断是否复用连接

7.2 用 curl 直接验证缓存相关响应头

你可以用下面这些命令快速确认服务端到底给了什么缓存策略:

bash 复制代码
curl -I https://example.com/static/app.js

重点关注:

  • Cache-Control
  • ETag
  • Last-Modified

如果你想验证协商缓存是否会返回 304:

bash 复制代码
curl -I https://example.com/static/app.js \
  -H "If-None-Match: <ETAG值>"

7.3 "改了资源但不生效"最常见的落地做法

  • 静态资源 带 hash 文件名 (例如 app.3f2a9c.js),配合长缓存
  • HTML 入口 短缓存/不缓存,保证能拿到新版本资源引用

8. 最后总结

8.1 常见状态码怎么归类理解

  • 2xx:成功(200)
  • 3xx:重定向/缓存(301/302/304)
  • 4xx:客户端错误(400/401/403/404)
  • 5xx:服务端错误(500/502/503)

8.2 复述自测(你能讲顺,说明你真的理解了)

HTTP 是应用层的请求-响应协议,通常跑在 TCP 之上,本身无状态,状态一般通过 Cookie/Session/Token 在应用层实现。HTTP/1.1 用 Keep-Alive 复用连接减少握手开销,但同一连接仍可能队头阻塞;HTTP/2 用二进制分帧和多路复用提升并发能力,同时做了头部压缩。缓存建议按"先强后协商"理解:强缓存靠 Cache-Control: max-age 让浏览器直接用本地;协商缓存靠 ETag/Last-Modified 让服务端决定是否返回 304。

相关推荐
AI 编程助手GPT27 分钟前
curl 返回成功就能收文件?用本地 HTTP 验证错误页与超时
网络·网络协议·http
十碗饭吃不饱2 小时前
后端运维:网络联通、进程查询、Java服务启动脚本
java·运维·网络
流浪0012 小时前
计算机网络篇16:传输层——TCP 报头属性字段:16 位窗口大小撑起流量控制,六个标志位标识报文类型
网络协议·tcp/ip·计算机网络·urg紧急指针·tcp报头
apollo_qwe2 小时前
接口超时了,前端为什么不能直接重试?
javascript·http
从琳开始9894 小时前
网络原理入门(二)------OSI七层模型?TCP/IP五层(四层)模型原来是这样的
java·网络·tcp/ip·java-ee·php
Jongkhurun5 小时前
以太网的最小帧长为什么是 64 字节:从 CSMA/CD 冲突窗口推导 64 Byte
网络协议
xiaoye-duck6 小时前
《C++ 项目:手写大模型接入 SDK》ChatGPT接口设计(下):流式响应实现和测试
网络·c++·语言模型·chatgpt
梦帮科技6 小时前
意识启发式量子隧穿退火算法用于全局优化 (CITA) 完整技术指南
网络·人工智能·算法·量子计算·模拟退火算法
坤坤子吖7 小时前
Linux网络编程:UDP进阶,从字典服务器到简单聊天室
linux·服务器·网络·c++·笔记·学习
爱和冰阔落8 小时前
【Linux网络】TCP 服务器怎么写?从 listen、accept 到 read/write,手写完整 Echo Server
linux·运维·服务器·网络