bigywater.tech
Rust · 140

HTTP 请求的底层实现

HTTP 客户端库替你做了哪些事?这篇不用任何 HTTP 库:自己拼请求文本、自己解析响应头、自己处理 Content-Length、EOF 与 chunked 三种正文结束方式,再和 curl 对照。

188 字节
最小的 GET /hello 请求得到的原始响应字节数
13
"hello 世界\n" 的 Content-Length(字节数,汉字各占 3 字节)
104 对 149 µs
复用连接与每次新建连接的平均请求耗时

请求与响应是文本

实测 · 本机执行输出
  编译:成功
  运行(退出码 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 与重定向

实测 · 本机执行输出
  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"]

分步演示

HTTP 请求
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。curl 8.7.1;服务端 Python http.server
    • 没有验证:HTTPS/TLS、HTTP/2 与 HTTP/3、请求体与 POST(Content-Length 与 chunked 的上传)、压缩 Content-Encoding、超大头部、响应拆分与安全问题、reqwest/hyper 等库的行为
    京ICP备2026067502号-1京公网安备11010502063487号