5.3 理解HTTP,手搓一个API
先不上框架:用手搓的方式学 HTTP 基础。语言会变、框架会变,HTTP 协议不会过时。
课时概要
先不上框架,把 HTTP 规范看明白,再用 Python 标准库 http.server 手搓一个 API(GET /api/profile 回 JSON)。一去回两段文本:请求行/头/空行/体,状态码家族,curl -v 和 F12 亲眼看到报文。为什么要手搓——因为杂活人人一样,下一节 FastAPI 替你干。
以上为 UP 主的 B 站官方简介,非观看笔记;只有跟完这一节才算自己的理解。
视频:【零到全栈】5.3-理解HTTP,手搓一个API | 时长 45:28 | 模块 5 · 初试后端
讲义:模块 5.3:看懂 HTTP,手搓 API(李勃老师.com)
本节要点
- API 用的对话协议就是 HTTP:浏览器开网页、Nginx 发 html、API 回 JSON,全是这套。我们之前只是没往里看。
- 一去回两段纯文本:请求 = 请求行(方法+路径+版本) + 头 + 空行 + 体;响应 = 状态行(版本+状态码+说明) + 头 + 空行 + 体,结构对称。
- 方法描述意图,不是数据方向:GET「给我」、POST「我提交内容请你处理」;响应永远有,与方法无关。curl 默认 GET,用了
-d自动变 POST。 - 状态码家族:2xx 成功、4xx 请求方的错、5xx 服务方的错。
- 回响应哪些不能省:状态行、空行是硬要求(缺了对方直接报错),
Content-Type实践必写(省了对方只能猜格式)。 Content-Type是「关于内容的说明」:内容不变、头从text/html改成text/plain,浏览器就从渲染网页变成显示裸标签。- 服务端天然看得见:User-Agent、来源 IP、语言偏好——ipify 能报你公网 IP 的根源就在这。
- 手搓全是重复杂活(路由/状态码/头/空行/体),任何语言写后端都是实现同一套规范——所以有了框架,下一节 FastAPI。
笔记正文(讲义整理)
HTTP 一去回
请求(去) 响应(回)
├─ 请求行 ├─ 状态行
│ 方法 路径 版本 │ 版本 状态码 说明
├─ 请求头(若干行) ├─ 响应头(若干行)
├─ (空行) ├─ (空行)
└─ 请求体(可选) └─ 响应体(JSON 在这)
curl -v 把报文全亮出来:> 发出去的请求、< 收到的响应、* 旁白跳过。我们平时看到的 {"ip":...} 只是响应体那一行。
方法和状态码(混个脸熟)
| 方法 | 意图 |
|---|---|
| GET | 把东西给我 |
| POST | 我提交内容请你处理 |
| PUT / PATCH / DELETE | 整体替换 / 改一部分 / 删掉 |
状态码:2xx 成功,4xx 你错了,5xx 我错了。404 模块 4 是 Nginx 替我们回的,现在轮到自己回。
手搓 API:main.py
python
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
profile = {"heroTitle": "关于我", "heroSubtitle": "…"}
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/api/profile":
self.send_response(200) # 状态行
self.send_header("Content-Type", "application/json") # 响应头
self.end_headers() # 那个必须的空行
body = json.dumps(profile, ensure_ascii=False)
self.wfile.write(body.encode("utf-8")) # 响应体
else:
self.send_response(404); self.end_headers()
HTTPServer(("", 8000), Handler).serve_forever()逐行对规范:do_GET 管方法、self.path 取路径、send_response 写状态行、send_header 写头、end_headers 是空行、wfile.write 是体。
bash
python3 main.py # 光标停住 = serve_forever 在等请求,Ctrl+C 停
curl http://localhost:8000/api/profile # 另开终端调它
curl -v http://localhost:8000/api/profile # 闭环:> 请求 < 响应,都是自己代码生成的两个实验
- 实验一(头的威力):
/hello返回<h1>你好</h1>,Content-Type: text/html时浏览器渲染成大标题;改成text/plain刷新——标签直接露出来。内容一字没变,头一变对方处理方式就变。 - 实验二(服务端看得见):
print(self.headers)看到 curl 和浏览器自动带的 UA 等头;print(self.client_address)看到来源 IP/端口。ipify 的谜底就在这。
和 GFG / 课程笔记的连接
| 这节内容 | GFG 笔记 / 已学 |
|---|---|
import json + json.dumps | GFG json 模块;ensure_ascii=False 让中文原样输出 |
class Handler(BaseHTTPRequestHandler) | GFG 的类与继承 |
self.path / self.wfile | GFG 里学过的面向对象——self 就是那个对象 |
http.server | 5.2 预告过的标准库成员,今天正式用上 |
| 端口 8000 | 2.4 讲过:IP 找机器,端口找机器上的程序 |
| 404 | 模块 4 是 Nginx 替我们回;现在自己回 |
你在 GFG 里多半用 requests 当调用方调过 API;今天第一次站到被调用方——角色对调,HTTP 这层纸就捅破了。
关键概念
- HTTP:两个程序对话的规范,API 只是用它回 JSON(而不是回 HTML)。
- 请求行 / 状态行:请求第一行(方法+路径+版本);响应第一行(版本+状态码+说明)。
- 请求头 / 响应头:一行一条的「附加说明」;
Content-Type说明体的格式。 - 空行:头和体之间的硬分隔,漏了全盘皆乱。
- 状态码:2xx 成功 / 4xx 请求方错 / 5xx 服务方错。
- 方法:GET/POST/PUT/PATCH/DELETE,描述请求意图。
- curl -v:把请求原文
>、响应原文<全打出来。
代码 / 实操
bash
# 启动自己的后端
source .venv/bin/activate
python3 main.py # serve_forever,Ctrl+C 停
# 另开终端验证
curl http://localhost:8000/api/profile
curl -v http://localhost:8000/api/profile
# 浏览器开 http://localhost:8000/api/profile ,F12 → Network 看同一套报文我的收获
- 「网页」和「API」从 HTTP 看没本质区别,都是一段响应,差别只在 Content-Type——做 API 就是选择回 JSON 而不是 HTML。
- 状态行、空行是硬要求,Content-Type 是实践必写——「规范必须」和「实践必写」的区别落到了代码上。
- 亲手搓一遍才知道框架替我们藏了多少活;下一节 FastAPI 缩成几行时,我知道它每一行在干什么。
待深入
(待填:没听懂、想回头查的。)