把 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-ControlETag

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

  • 队头阻塞(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

相关推荐
NGC_66112 小时前
TCP可靠传输怎么实现的
服务器·网络·php
橘子132 小时前
ICMP协议
运维·服务器·网络
遥遥晚风点点2 小时前
JAVA http请求报错:unable to find valid certification path to requested target
java·网络·网络协议·http
taxunjishu2 小时前
EtherNet/IP 转 TCP/IP 网关方案助力工业自动化欧姆龙PLC产线设备互通
网络·物联网·自动化
yunjingtianhe3 小时前
雨量监测器—实时测量和记录降水量
网络
Oll Correct3 小时前
实验六:以太网交换机自学习和转发帧的过程
网络·笔记·学习
wregjru3 小时前
【网络】7.网络层:IP 协议详解
网络·智能路由器
德迅云安全-如意3 小时前
DDoS是什么?遇到后有哪些解决方法?
网络·安全·ddos
木井巳3 小时前
【网络原理】HTTP协议
java·网络·网络协议·http·fiddler