🌐 第四章 Web网站的运行原理
📄 一句话概括

HTTP(HyperText Transfer Protocol,超文本传输协议)就是浏览器和 Web 服务器之间的对话规矩:一问一答。浏览器递上一张请求报文(三部分:起始行 / 头部 / 正文),服务器回一张响应报文(结构一样,起始行换成状态行)。两张纸的规矩完全相同:头部一行一个"名字: 值",然后一个空行,之后才是正文。这场对话有三条脾气要记住:服务器永远不主动开口;服务器不记得你是谁(这就是"无状态",也解释了为什么需要 Cookie);而响应开头那三位数字(状态码),是全世界排障最快的暗号——看第一位就知道该怪谁。

📝 本节和前面几节的分工

4.1 看见的是"网站由四件套构成、门房守着 80/443";4.2 与 4.3 拆开了"内容文件"本身;4.4 把地址讲透,并且在结尾留下了一个悬念——URL 的六段里,只有"路径 + 查询串"装进请求行发出去。

本节就从那行请求行往下写:它后面还跟着什么、服务器怎么回、那些字头各自管什么、状态码怎么看。

一、HTTP 是什么

HTTP = HyperText Transfer Protocol = 超文本传输协议。 逐词拆:

词 意思 说人话
HyperText(超文本) 带链接的文本 就是 4.2 那个 HTML——能点着跳来跳去的文本
Transfer(传输) 搬运 把网页从服务器搬到浏览器
Protocol(协议) 规矩 双方约定好的说话格式(收 1.6"协议=通信语言")
📝 HTTP 只管"说什么",不管"怎么送到"

它在应用层(收 1.6 的四层地图)。脚下踩着两双鞋: - TCP 负责可靠地把字节送到(收 3.18:分段、编号、丢了重发) - IP 负责找路(收 3.7)

所以 HTTP 自己完全不用担心"路上会不会丢"——它只负责把规矩写好。这就是 1.6 "分层"最实际的好处:每层只管自己那件事。

⚠️ HTTP 不是"浏览器专用",也不等于"网页"

curl 在用它、手机 App 在用它、后台服务之间也在用它;传的不只是网页,还有 图片、JSON 数据、上传的文件。

判断依据是内容里写明了是什么(Content-Type),而不是"它长得像不像网页"。

版本简史(知道差别就够):

版本 关键变化 解决什么
HTTP/1.0 一问一答,问完就断线 最早的规矩
HTTP/1.1 持久连接(一条连接上问好几轮)+ 必须带 Host 头 不用为每个文件重新握手;一台服务器能挂多个网站
HTTP/2 一条连接上并行跑多路 + 头部压缩 页面资源多时更快
HTTP/3 改跑在 UDP 上(收 3.20) 弱网下更抗丢包
💡 顺手回答 4.1 留下的问题

网页要几十上百次请求,为什么还不太慢?因为 HTTP/1.1 的持久连接——那几十次都跑在同一条已经建好的连接上,不必每个文件都重新握手。

二、一问一答:请求报文

浏览器发出去的那张纸,只有三部分(配图一左):

① 起始行(请求行)——一行讲完全部要点:

GET /index.html HTTP/1.1
 │        │          └── 用哪个版本的规矩说话
 │        └───────────── 要的东西(只有路径,没有域名!)
 └────────────────────── 方法:我要做什么

② 头部字段——一行一个「名字: 值」,是这场对话里所有"附加说明"的家:

请求头 说的是什么 说人话
Host 要哪个站 HTTP/1.1 必须带,一台服务器多网站全靠它分流
User-Agent 我是谁 浏览器类型与版本,网站靠它做兼容
Accept / Accept-Language 我能看懂什么、要哪种语言 会不会给你中文页,看它
Referer 我从哪个页面点过来的 统计来源(也涉及隐私)
Cookie 我的身份凭证 下一节的主角
Connection 这条连接怎么用(如 keep-alive) 别问完就断,留着继续用

③ 空行 + 正文——那个空行是硬规定,服务器靠它知道"头部到此为止"。

三、一问一答:响应报文

服务器回的那张纸,结构一模一样,只是把第一行换了名字(配图一右):

① 状态行:HTTP/1.1 200 OK —— 版本 + 三位数字 + 一句人话

② 响应头——这里的几个关键角色:

响应头 说的是什么 为什么重要
Content-Type 正文是什么内容 浏览器靠它决定怎么显示——是网页、图片还是 JSON。⚠️ 不是靠文件后缀(4.2 说过的"后缀无所谓"就是这个道理)
Content-Length 正文多少字节 对面知道该收多少才停(收 3.18 分段与长度)
Cache-Control / ETag / Last-Modified 这份东西能缓存多久、怎么判断有没有变 决定你下次打开快不快(收 3.21 缓存的老思路)
Set-Cookie 给你一张身份证 下一节的引子
Server 门房是谁(nginx / Apache / IIS) 4.1 里 curl -I 认门房看的就是它

③ 空行 + 正文:正文就是你要的东西本身——HTML 文本、图片的二进制、JSON 数据……这才轮到浏览器去看内容。

📝 头部是"给程序看的",正文才是"给人看的"

一张报文里,头部字段全是给浏览器、缓存、代理这些程序读的"说明标签";正文才是最终呈现在你眼前的东西。

这也是一句老话的来源:"东西明明下载下来了,打不开是因为类型不对"——正文拿到了,但 Content-Type 说不认识。

四、状态码:三位数字里的一整套语言

状态行的第一个重点就是那三位数字。第一位就决定了它属于哪一族(配图二),剩下的两位是族内的具体编号。

族 含义 谁的问题 你该干什么
1xx 信息,还在处理 都不是 极少见,不用管
2xx 成功 都不是 正常
3xx 重定向,去新地址 都不是 浏览器会自动跟着跳
4xx 客户端出错 你这边的请求有问题 先查自己:地址写错?没登录?没权限?
5xx 服务器出错 服务器那边有问题 你改也没用,等一等或找运维

最常撞见的几个,逐个认脸:

💡 排障第一句口诀

4 开头先查自己,5 开头先问服务器。

这一条能省下大量"是不是我网络坏了"的无效怀疑。

五、HTTP 是"无状态"的

这是 HTTP 最重要的性格:每一个请求都是独立的一张纸,服务器不会记得上一个请求。

📝 为什么故意这么设计

因为它简单、好扩展:任何一台服务器收到任何一个请求,只看这张纸就能干活,不需要"知道之前发生过什么"。

这样一来,一台忙不过来可以再加一台(收 1.7 的弹性伸缩),你这次请求打到哪台机器上都一样。

代价也很具体:登录、购物车、多步表单这些"要记住"的事,HTTP 本身做不到。于是有了补丁——Cookie:

  1. 第一次你去,服务器在响应头 Set-Cookie 里塞给你一张小纸条
  2. 之后每次请求,浏览器在请求头 Cookie 里自动带上这张纸条
  3. 服务器一看纸条:哦,是老熟人

一张纸条把"无状态"的对话接成了"有记忆"的对话。这就是为什么清掉 Cookie 之后,很多网站会把你当成陌生人。

六、一次页面加载,其实是好几轮对话

把 4.1 的账本和本节合起来看:一次打开网页 = 几十上百次请求 = 几十上百轮一问一答,每一轮都各自有一对完整的报文。

顺序也很讲究(收 4.2):

  1. 先要 HTML(1 次)
  2. 浏览器边读边发现:"还要一个 CSS、两个 JS、三张图"
  3. 于是再各要一次(每个都是一轮完整的请求-响应)

所以"页面一点点长出来"其实很直观:HTML 先到,其余的东西一轮一轮补进来。

七、动手 Demo(Demo42)

目标:把 F12 里那一堆"标头",和本节图一的三段结构对上号。

第 1 步 · 用 curl -v 看报纸原件(最直观的一步)

curl -v https://example.com

找两批行:> 开头的是你发出去的请求、< 开头的是服务器回的响应。对照图一,一行一行认。

第 2 步 · 只要头部:curl -I

curl -I https://example.com

这就是 HEAD 方法(只取头部不要正文),输出里能看到 Server(认门房)、Content-Type(是什么内容)、Cache-Control(能缓存多久)。

第 3 步 · 在 F12 里对上图一的左右两半 F12 → 网络 → 随便点一条请求 → 「标头」里分成请求标头和响应标头两堆。把图一那两个面板摆在旁边对,一次就记住了。

第 4 步 · 亲手改一次方法

curl -X POST -d "name=bozai" https://httpbin.org/post

看回显里 "form" 那一栏——你 POST 的正文被服务器读出来了。这也证明:GET 要东西、POST 递东西。

第 5 步 · 故意撞 404 和 301 - 访问一个不存在的路径(如 curl -I https://example.com/nope)→ 看状态行变成 404 - 用 curl -I http://example.com(不带 www)→ 常能看到 301 和一个 Location: 头——这就是"搬家了去新地址"的实物

第 6 步 · 抓一次 304(缓存在干活) 刷新页面,然后再刷新一次,在网络面板里看静态资源那条:状态会变成 304 或"来自缓存",大小几乎为 0。 这就是"第二次打开更快"的机制(收 3.21 缓存)。

第 7 步 · 看 Cookie 一进一出 F12 → 应用 → Cookie 里看有哪些;再回网络面板,找响应头里的 Set-Cookie 和请求头里的 Cookie——一张纸条怎么发出去、怎么带回来,全在眼前。

第 8 步 · 用 4.2 那个门房日志再品一次

python -m http.server 8000

刷新页面,看窗口里一行行刷出来的记录——每刷一行,就是一轮刚刚完成的 HTTP 对话。

八、30 秒实验

  1. 30 秒:curl -v https://example.com 之后,数一数 > 有几行、< 有几行——图一是示意,这才是真货。
  2. 30 秒:curl -I https://example.com/不存在的页面,看状态行从 200 变成 404。
  3. 30 秒:在 F12 里随便点一条请求,只看 Content-Type——是 text/html、image/png 还是 application/json?看三个你就明白"内容类型"这回事了。

九、常见误区

  1. "HTTP 就是浏览器用的、就是网页。" —— 它是通用的对话规矩,curl、App、后台服务都在用;传的也不只是网页。
  2. "请求行里怎么没有域名?是不是我看漏了。" —— 域名在 Host 头里(收 4.4)。请求行只有方法 + 路径 + 版本。
  3. "404 就是网站挂了。" —— 404 是东西不在(多半地址写错)。网站挂了更像 5xx 或干脆连不上。
  4. "返回 200 就说明没问题。" —— 200 只说"请求被正确处理了"。内容对不对,还得看正文。
  5. "文件类型看后缀不就行了。" —— 浏览器看的是响应头 Content-Type,不是后缀(4.2 已埋过这条)。
  6. "一次请求就是一个页面。" —— 一次页面加载是几十上百轮对话(收 4.1)。
  7. "HTTP 记得我上次来过。" —— 无状态。记得你的是 Cookie,不是 HTTP。
  8. "304 是个错误。" —— 304 是好消息:你手里的缓存还能用,省下一次下载。
  9. "头部字段随便写、不写也无所谓。" —— HTTP/1.1 里 Host 必须带,Content-Type 不带浏览器就可能不认。
  10. "HTTPS 是另一套协议,报文结构不一样。" —— HTTPS 就是 HTTP 外面套了一层加密,报文内容一点没变(4.4 说过:那是"穿不穿衣服"的区别)。

十、动手自测

❓ 自测一下
  1. HTTP 三个字母是什么?它在哪一层?下面踩着谁?
  2. 请求报文和响应报文各由哪几部分组成?那个"空行"是干什么用的?
  3. 请求行里有哪三样东西?为什么没有域名?
  4. GET 和 POST 最本质的区别是什么?
  5. 哪个响应头决定浏览器把正文当网页还是当图片?它和后缀是什么关系?
  6. 状态码有哪五族?各是谁的问题?
  7. 301 和 302 差在哪?304 又是什么?
  8. "HTTP 是无状态的"是什么意思?那登录状态靠什么维持?
  9. 一次页面加载为什么是"几十上百轮对话"?这些对话是怎么排队的?
  10. HTTPS 和 HTTP 的报文结构一样吗?区别在哪?

答案: ① HyperText Transfer Protocol(超文本传输协议),在应用层;下面踩着 TCP(可靠送到)和 IP(找路)——所以 HTTP 自己不管会不会丢。 ② 都是三部分:起始行 + 头部字段 + 空行 + 正文(响应报文的起始行叫状态行)。空行是硬规定,用来告诉对方"头部到此为止,后面是正文"。 ③ 方法 + 路径 + 版本(如 GET /index.html HTTP/1.1)。没有域名,因为域名在 Host 头里——一台服务器挂多个网站,得靠它分流(收 4.4)。 ④ GET 是"把东西给我"(要),POST 是"带着数据去提交"(给)。所以 GET 一般没有正文,POST 有正文。 ⑤ Content-Type。浏览器只看它,跟文件后缀无关(4.2 那条"后缀无所谓"就是从这来的)。 ⑥ 1xx 信息 / 2xx 成功 / 3xx 重定向 / 4xx 客户端出错 / 5xx 服务器出错;4 开头先查自己,5 开头先问服务器。 ⑦ 301 永久搬家(浏览器会记住新地址,下次直接去)、302 临时(每次都还得问一下);304 不是错误,是"你手里那份还能用,别下了"——缓存在省的流量。 ⑧ 意思是每个请求都是独立的一张纸,服务器不记得上一个请求(换来的是简单、好扩展、能随意加机器)。登录状态靠 Cookie:服务器用 Set-Cookie 发一张纸条,浏览器之后每次请求都自动带回去。 ⑨ 因为每个 CSS、JS、图片都要各要一次(收 4.2),而且先拿到 HTML 才知道还要什么——所以只能一轮一轮来。它们大多跑在同一条持久连接上(HTTP/1.1 的功劳),所以还不太慢。 ⑩ 完全一样。HTTPS 只是把整条 HTTP 报文套进加密通道里(4.4 说的"穿不穿衣服"),报文的三段结构、头部、状态码都没变。

十一、下一步学什么

相关笔记