HTTP 客户端库替你做了哪些事?这篇不用任何 HTTP 库:自己拼请求文本、自己解析响应头、自己处理 Content-Length、EOF 与 chunked 三种正文结束方式,再和 curl 对照。
编译:成功
运行(退出码 0):
请求(59 字节):"GET /hello HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n"
响应共 188 字节;按 \r\n 显示:
| HTTP/1.1 200 OK
| Server: BaseHTTP/0.6 Python/3.14.7
| Date: Thu, 01 Oct 2026 15:55:00 GMT
| Content-Type: text/plain; charset=utf-8
| Content-Length: 13
| X-Demo: a
| X-Demo: b
|
| hello 世界⏎TCP 的基础见TCP Listener 与 TcpStream。服务端用 Python 3 自带的 http.server(独立实现,方便对照),监听本机系统分配的端口。
编译:成功
运行(退出码 0):
状态行 "HTTP/1.1 200 OK" → 版本 HTTP/1.1 状态码 200 原因短语 "OK"
头部(键转小写)共 6 个:[("server", "BaseHTTP/0.6 Python/3.14.7"), ("date", "Thu, 01 Oct 2026 15:55:01 GMT"), ("content-type", "text/plain; charset=utf-8"), ("content-length", "13"), ("x-demo", "a"), ("x-demo", "b")]
Content-Length = 13,实际正文 13 字节:"hello 世界\n"(中文 "世界" 在 UTF-8 里每字 3 字节,所以 length 是字节数)
同名头 X-Demo 出现 2 次:["a", "b"](头部可以重复) 编译:成功
运行(退出码 0):
/close 的响应头里有 Content-Length 吗: false;正文靠读到 EOF:"no length, ends when the server closes"
/chunked 的原始正文:"6\r\nfirst-\r\n7\r\nsecond-\r\n5\r\nthird\r\n0\r\n\r\n"
手写分块解码(十六进制长度 + 数据,0 结尾)得到:"first-second-third" 编译:成功
运行(退出码 0):
同一连接上的第 1 个请求:"HTTP/1.1 200 OK",正文 13 字节(本地端口没变: true)
同一连接上的第 2 个请求:"HTTP/1.1 200 OK",正文 13 字节(本地端口没变: true)
500 个请求,每个请求平均:复用连接 104 µs,每次新建连接 149 µs耗时是本机回环地址的结果。从 Socket 到完整 HTTP 服务端见HTTP Server 从 Socket 到 Response。
curl -i /redirect(不跟随):
HTTP/1.1 302 Found
Server: BaseHTTP/0.6 Python/3.14.7
Date: Thu, 01 Oct 2026 15:55:02 GMT
Location: /hello
Content-Length: 0
curl -L /redirect(跟随)得到正文:'hello 世界'
服务端看到的请求头(curl 默认会加这些):
Host: 127.0.0.1:56145
User-Agent: curl/8.7.1
Accept: */*
X-Trace: 1
编译:成功
运行(退出码 0):
我们手写的最小请求,服务端看到的请求头:["Host: 127.0.0.1", "Connection: close"]