企业网络、翻墙工具、抓包软件都离不开 HTTP 代理。明文 HTTP 经代理时请求行有什么不同?HTTPS 为什么要 CONNECT?代理到底能看到什么、不能看到什么?代理多花了几个往返?这篇自己写了一个最小代理,在本机把这些问题逐个量出来。
客户端经代理发出的请求行:GET http://example.com/ HTTP/1.1 直连时的请求行是:GET / HTTP/1.1(origin-form,只有路径);经代理变成了 absolute-form,因为代理需要知道要连哪台主机 代理收到的头部名字:['host', 'user-agent', 'accept-encoding', 'accept', 'connection'];代理转发请求时加了 Via: 1.1 w83proxy,去掉了 Proxy-* 和原来的 Connection 头(改成 Connection: close);最终客户端拿到 200,577 字节 代理能看到什么:完整 URL、全部头部(包括 Cookie / Authorization 等)和整个消息体——明文 HTTP 对代理是完全透明的
请求行用绝对形式带完整 URL;代理看得到一切并可以修改头部。
客户端发给代理的第一行:CONNECT example.com:443 HTTP/1.1;代理回复 200 Connection Established;之后客户端 200,收到 577 字节 代理中转的字节:客户端→服务器 1751 字节,服务器→客户端 6544 字节(都是 TLS 密文) 代理在转发的第一批字节里看到的 TLS ClientHello 里的 SNI(服务器名,明文)= example.com;它看不到 URL 路径、头部、Cookie 和消息体 客户端校验的证书是 example.com 自己的(不是代理的):requests 成功且没有证书错误——说明隧道是端到端的 TLS
代理回 200 之后只搬字节;TLS 是端到端的,代理看到 CONNECT 目标和 SNI,看不到 URL 与内容。
直连:[529, 490, 522, 689] ms,中位 525 ms 经代理(客户端↔代理 往返 100 ms):[1889, 1114, 1208, 1047] ms,中位 1161 ms 经代理多出 636 ms(中位数之差) 直连各阶段(中位 ms):TCP 连到源站 157;TLS 握手 188;HTTP 请求到首字节 375;合计 720 经代理各阶段(中位 ms):连到代理 101;CONNECT 往返 264;TLS 握手 362;HTTP 请求到首字节 472;合计 1199 对照:TLS 握手和 HTTP 请求这两个阶段,经代理的耗时比直连多出的部分,就是隧道里多经过的那一段 100 ms 往返(客户端↔代理)
每个原本的往返现在都多穿过一段客户端↔代理;连到代理 1 个 RTT,CONNECT 再 1 个 RTT。
CONNECT 到被禁止的主机:代理返回 403;客户端 → ProxyError:HTTPSConnectionPool(host='blocked.example', port=443): ProxyError('Unable to connect to pr
CONNECT 到连不上的目标(127.0.0.1:9):代理返回 502;客户端 → ProxyError:HTTPSConnectionPool(host='127.0.0.1', port=9): ProxyError('Unable to connect to proxy', OS
代理要求认证:不带凭据 → 状态 407,Proxy-Authenticate = Basic realm="w83"
带上凭据(Proxy-Authorization: Basic …)→ 状态 200;代理收到的 Proxy-Authorization = Basic dXNlcjpwYXNz(Basic 只是 base64 编码:user:pass,不是加密)403 / 502 对客户端都是 ProxyError;407 要求 Proxy-Authorization,Basic 只是 base64。