请求是一句有格式的话:方法 + 地址 + 版本;而【无状态】说的是——发送完这一句,服务器就把你忘了。
2-5 讲了页面是提前做好的还是现场做的,但还没讲清楚【请求】这个东西本身。从这一条起连着三条讲 HTTP 的两半:请求(客户端说什么)、响应(服务器答什么)、以及去哪里看这两半。
一、请求长什么样
一行标题,就交代了三个信息:用哪个方法、要哪个东西、用哪个版本的协议。
这一行下面跟着一串请求头:Host 说明你要的是哪个域名下的资源(一台服务器常常挂着好几家网站),User-Agent 说明你是谁、Accept 说明你能接受什么格式,Cookie 就是你带上的那一小段凭证。
二、方法:八个词,常用五个
GET 取回来,POST 交上去——这两个占了绝大多数。
剩下几个里,HEAD 是【只要说明不要正文】,DELETE 和 PUT 是删与改,OPTIONS 是问服务器支持什么。它们不是不重要,而是在一个典型网站的流量里占比很小。
三、动手 Demo:方法表与真实流量
rows = [("GET", 68, "取页面、取样式、取图片都算它"),
("POST", 23, "表单提交、接口调用"),
("HEAD", 8, "多半是监控和健康检查在敲门"),
("其他", 1, "预检、探测、扫描")]
for m, p, note in rows:
print("%-6s %3d%% %s" % (m, p, note))
实跑输出:
--------------------------------------------------------------------
D6 Web 网站的 HTTP 请求:无状态、HTTP 请求、HTTP 方法
--------------------------------------------------------------------
浏览器发给服务器的每一条消息,都叫一次【请求】。开头是三个词:
GET /index.html HTTP/2
方法 路径 协议版本
方法一共有八个,日常常用的就是前五个:
----------------------------------------------------------------------------------------
方法 干什么 安全 幂等 能缓存
----------------------------------------------------------------------------------------
GET 把东西取回来 是 是 能
HEAD 只要响应头,不要正文 是 是 能
POST 提交数据、新建一条 否 否 一般不能
PUT 整条替换掉 否 是 不能
PATCH 只改一部分 否 否 不能
DELETE 删掉 否 是 不能
OPTIONS 问服务器支持什么 是 是 不能
----------------------------------------------------------------------------------------
【安全】的意思是【不改动服务器上的东西】;
【幂等】的意思是【做一次和做十次,结果一样】。
把这两列记住,就不会问出【能不能用 GET 删数据】这种问题。
真实流量里各方法占多少(一个典型站点的访问日志):
----------------------------------------------------------------------------------------
方法 占比 说明
----------------------------------------------------------------------------------------
GET 68% 取页面、取样式、取图片都算它
POST 23% 表单提交、接口调用
HEAD 8% 多半是监控和健康检查在敲门
其他 1% 预检、探测、扫描
----------------------------------------------------------------------------------------
那么打开一个页面,到底发了多少条请求?
----------------------------------------------------------------------------------------
资源类型 请求数
----------------------------------------------------------------------------------------
HTML 文档 1
CSS 样式 8
JavaScript 24
图片 31
----------------------------------------------------------------------------------------
合计 64
----------------------------------------------------------------------------------------
64 条里,63 条是 GET,0 条是 POST——
【取回来看】占了绝大多数,【提交上去】只在点按钮那一下发生。
最后说【无状态】这个词,它是这一条里最容易被念错的:
服务器处理完一条请求,就把这次见面忘了。
下一条请求进来,在它眼里又是【头一回见面】。
这对服务器是好事。假设每秒 8000 条请求:
它不需要为 8000 个人各留一个座位,任何一台服务器都能接任何一条请求;
坏了一台,另一台直接接着干,不用搬座位。
代价是:服务器【记不住你】。想让它记住,就得让浏览器每次自己带上凭证——
那就是 2-13 的 Cookie 和 2-14 的会话要做的事。
读这个输出:GET 一个人占了近七成。这不奇怪——打开一个页面要取 HTML、取样式、取脚本、取一堆图片,全是 GET;而 POST 只在【点按钮】那一下发生。记住这个比例,就能明白为什么 GET 会被特别强调【安全】和【可缓存】。
四、无状态:不是缺陷,是设计
【无状态】这个词说的是:服务器处理完一条请求,就把这次见面忘了。下一条请求进来,在它眼里又是头一回见面。
这对服务器是好事。假设每秒 8000 条请求——它不需要为 8000 个人各留一个座位;任何一台服务器都能接任何一条请求,坏了一台,另一台直接接着干。
代价是服务器记不住你。要它记住,就得让浏览器每次自己带上凭证——这就是 2-13 的 Cookie 和 2-14 的会话要解决的事。
所以这条线是连着的:HTTP 故意不记人 → 需要 Cookie 来补 → Cookie 会过期 → 需要会话来串起一连串操作。教材把这一条放在 Cookie 前面七节,不是顺序凑巧。
30 秒实验
- 按 F12 打开开发者工具,切到 Network 面板,然后刷新页面。
- 随便点一条请求,看它的 Method 那一列是什么——猜猜一共有多少条是 GET。
- 再找一个你填过表、点过提交的页面重复这个过程,找出那个 POST,看看它和 GET 有什么不一样。
常见误区
- 错误:GET 和 POST 的区别就是【一个在地址栏、一个在请求体】。——纠正:它们表达的是两种意图:GET 是【取回来看】,POST 是【提交上去改点什么】。地址栏和请求体只是实现方式。意图不同,带来的是能不能缓存、能不能重复执行、能不能被预取这一整套差别。
- 错误:无状态是个缺陷,早晚要改掉。——纠正:它是故意的,而且是 Web 能扩展到今天这个规模的关键之一。没有状态,任何一台服务器都能接任何一条请求;有状态就得让服务器互相通报,成本高得多。
- 错误:既然是无状态,服务器就是完全不认人的。——纠正:协议本身不认人,但应用层可以加上记性。Cookie 与会话就是加在外面的那层记性。分清【协议不带状态】和【服务器不知道你是谁】这两件事,是理解后面几节的关键。
- 错误:请求头都是可有可无的装饰。——纠正:它们决定了这次请求怎么看、给不给、怎么给。Host 决定去哪个网站(一台服务器可以挂很多站)、Accept-Encoding 决定要不要压缩、Cookie 决定认不认得你。少一个,结果可能就不一样。
自测三问(点开对答案)
1. 为什么 GET 在真实流量里占近七成? —— 因为**打开一个页面就要取很多东西**:HTML、样式、脚本、图片,每一样都是一次 GET(见 1-6 的渲染路径)。而 POST 只在用户真正提交的时候发生。**所以【流量结构】其实是【页面结构】的投影。** 2. 无状态给服务器带来的最大好处是什么? —— **任何一台服务器都能接任何一条请求**。不需要给每个访问者留位置,也就不需要让服务器之间互相通报——**这才撑得住横向扩展**:不够就加机器,加上去就能干活。 3. 为什么教材要把无状态和 Cookie 分成两节讲、还隔了七节? —— 因为**它们是两个层面的东西**:无状态是协议的设计,Cookie 是在协议外面加上去的一层记性。**先讲清楚协议为什么不记人,才能讲清楚那层记性是必要的、以及它是怎么补上去的。**- ☐ 下一节(2-7 Web网站的HTTP响应:HTTP 响应、状态码)
相关笔记
- 静态页面与动态页面 —— 上一节:这一句请求会得到什么样的回答
- 请求Web网站的文件(HTTP) —— 网络课里的请求
- HTML、HTTP —— 编程课里的 HTTP
- 🕸️ Web技术原理 · 索引