代理服务器是一台替你的电脑去连网站的机器。你的连接到它那里为止,它再用自己的地址去连网站,网站看见的来客是它。打开一个网页要走七步,查域名、连 TCP、说一句 CONNECT、TLS 握手、发请求、收回包、留记录,经过代理时查域名和连网站这两步换成代理去做,中间多出一句你对代理说的 CONNECT,第四步起网站只认你的电脑,代理在旁边能看见域名和流量大小。2026-10-29 我在自己的电脑上用 curl 8.19.0 把直连和经代理各跑了一遍,差别全在 -v 打出来的那几十行里,下面逐步对着看。
本页讲的代理只指网络里替你转发连接的这种机器,专利、招标、保险那些行当里的代理人和它没有关系。
我的环境交代一句。电脑上装着 Clash Verge,它带的 mihomo 内核在 127.0.0.1:7897 开了一个混合端口,HTTP 和 SOCKS5 两种写法都认,下面所有经代理的命令都指向这个端口。它背后连的是哪家的哪个节点,这页不管,只看你的电脑和这个端口之间发生了什么。输出里带着我本机地址的那半句我删掉了,域名解析出来的公网地址照原样留着,引用的规范和文档都是当天打开核对的。
七步是哪七步,两种走法并排看
| 步 | 这一步做什么 | 直连时谁做 | 经代理时谁做 | 终端里对应的那一行 |
|---|---|---|---|---|
| 1 查域名 | 把 example.com 换成 IP 地址 | 你的电脑 | 代理 | 直连有 Host example.com:443 was resolved.,经代理没有这一行 |
| 2 连 TCP | 和 443 端口建立连接 | 你的电脑连网站 | 你连代理,代理连网站 | Established connection to example.com 变成 Trying 127.0.0.1:7897... |
| 3 说 CONNECT | 告诉代理要去哪 | 没有这一步 | 你对代理说 | > CONNECT example.com:443 HTTP/1.1 与 < HTTP/1.1 200 Connection established |
| 4 TLS 握手 | 对证书、定密钥 | 你的电脑和网站 | 还是你的电脑和网站,穿过隧道 | 两种走法都有 ALPN: curl offers http/1.1 |
| 5 发请求 | 把 GET 发出去 | 直接发 | 在隧道里发 | 两种走法都是 > GET / HTTP/1.1 |
| 6 收回包 | 收状态行和页面 | 网站直接回 | 原路穿隧道回来 | < HTTP/1.1 200 OK,后面跟着 Server: cloudflare |
| 7 留记录 | 谁在哪本账上记了什么 | 网站记你的地址 | 网站记代理的地址,代理另记一笔 | curl -v 不显示,要去各家的日志里找 |
表里只有第三步是代理独有的。其余六步两种走法都有,差别在谁来做、在哪台机器上做。往下我按步拆开,每一步贴出终端里的原文。
第一步查域名,直连时是你的电脑在查
直连那次,curl 开头就报了这几行。
终端 · curl -v https://example.com/(直连,节选)
* Host example.com:443 was resolved.
* IPv6: 2606:4700:10::6814:179a, 2606:4700:10::ac42:93f3
* IPv4: 104.20.23.154, 172.66.147.243
* Trying [2606:4700:10::6814:179a]:443...是我的电脑去问了 DNS,拿回两个 IPv6 和两个 IPv4,挑第一个去连。换成经代理,这几行整段消失,curl 的第一句就是 Trying 127.0.0.1:7897...,域名原封不动塞进了第三步那句 CONNECT 里,交给代理去查。我用 -w 把每一步的耗时打了出来,三次直连的域名解析用了 5 到 13 毫秒,三次经代理都不到 0.04 毫秒,本机根本没有东西要解析。
这一步在谁手里,决定了谁的 DNS 日志里会出现你要去的域名。SOCKS5 代理这里有个容易踩的坑。curl 文档里 socks5:// 和 socks5h:// 是两种写法,带 h 的那种才由代理解析域名 [1]。两种我都跑了,socks5:// 那次 curl 照样打出 Host example.com:443 was resolved. 和四个地址,socks5h:// 那次没有。SOCKS5 协议本身允许请求里直接放域名,RFC 1928 给地址类型留了 X’03’ 这个值,专门装域名 [2],用不用它,看客户端怎么写。
| 代理写法 | 域名谁查 | curl -v 里的证据 |
|---|---|---|
http://127.0.0.1:7897 |
代理 | 没有 was resolved 这一行,域名在 CONNECT 里 |
socks5://127.0.0.1:7897 |
你的电脑 | 有 was resolved,列出四个地址 |
socks5h://127.0.0.1:7897 |
代理 | 没有 was resolved,只有 Opened SOCKS connection ... to example.com port 443 |
第二步和第三步,TCP 连到谁,CONNECT 对谁说
直连时 curl 写得很直白,Established connection to example.com (2606:4700:10::6814:179a port 443),我的电脑和网站的 443 端口之间有了一条 TCP 连接。经代理时这条连接的另一头换成了本机的 7897 端口,接着多出一段对话。
终端 · curl -v -x http://127.0.0.1:7897 https://example.com/(节选)
* Establish HTTP proxy tunnel to example.com:443
> CONNECT example.com:443 HTTP/1.1
> Host: example.com:443
> User-Agent: curl/8.19.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection established
<
* CONNECT phase completed
* CONNECT tunnel established, response 200我的电脑对代理只说了一件事,去 example.com 的 443 端口。代理回一句 200,从这行以后两边都切成隧道模式,代理只搬字节。RFC 9110 把 CONNECT 定义为请求对方建一条通到目标源站的隧道,并写明它就是给代理用的,隧道任何一头断开,中间人就把另一头也收掉 [3]。代理和网站之间那条真正出门的 TCP 连接,curl 一个字都看不到,它连的只是本机的 7897。耗时上也看得出来,三次经代理的 connect 都在 1 毫秒以内,走的是本机回环,直连的三次是 58 到 265 毫秒,那才是去网站的路。
MDN 那页提了一句,有的代理不支持 CONNECT,或者只允许连 443 端口 [4]。公司里的代理常这样配,非标准端口的服务在公司网里连不上,多半卡在这一步。
第四步 TLS 握手,证书是网站的,代理只听到一个名字
两种走法在这一步打出的行一模一样,ALPN: curl offers http/1.1 和 ALPN: server accepted http/1.1。握手是我的电脑和网站两头做的,证书是网站的证书,密钥只在这两头。经代理时这些包穿过第三步建好的隧道,代理搬运它们,拆不开。
代理能看到的是域名。TLS 握手的第一个包 ClientHello 里带着 server_name 扩展,RFC 6066 加这个扩展是为了让一个地址上挂着多个站的服务器知道你找哪一个 [5],它和这个包里的其他内容一样没有加密。2026 年发布的 RFC 9849 把话说得更重,明文 SNI 泄露目标域名,大概是 TLS 1.3 里留在明文中最敏感的一项信息,这份文档定义的 ECH 就是为了把它也加密 [6]。我顺手请求了 Cloudflare 的 trace 接口,返回里有一行 sni=plaintext 和一行 tls=TLSv1.3,直连和经代理都是这两个值,我这台电脑上的 curl 还没有用上 ECH。
所以带锁的网页,代理默认看不见内容,看得见你去了哪个域名、什么时候、传了多少字节。有一种情况例外。公司网络里做 TLS 检查的设备会把一条连接拆成两条,一条从你的浏览器到它,一条从它到网站,中间用它自己签发的证书,前提是先把公司的根证书装进每台电脑的信任列表 [7]。Cloudflare 的网关文档也写着同样的前提,不装它的证书,完整网址、头部和请求体它都看不到 [8]。点开浏览器地址栏的锁,看证书是谁签的,签发者写着公司自己的名字,那就是这种情况。
第五步发请求,明文 HTTP 和隧道里的 HTTPS 是两种样子
隧道建好以后,curl 发出的请求和直连时逐字相同。
终端 · 隧道里的请求(两种走法相同)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/8.19.0
> Accept: */*这四行在隧道里是加密过的字节,代理记不下来。我又把网址换成 http://example.com/,没有 s,经同一个代理再跑一遍,样子就变了。
终端 · curl -v -x http://127.0.0.1:7897 http://example.com/(节选)
> GET http://example.com/ HTTP/1.1
> Host: example.com
> User-Agent: curl/8.19.0
> Accept: */*
> Proxy-Connection: Keep-Alive请求行里写的是完整网址,还多了一行 Proxy-Connection,这是把整个请求交给代理去转发的写法。代理读完请求,自己去连网站,拿到回复再转给我。它有没有真的读过,看回包就知道。直连时网站回的头部是 CF-RAY、cf-cache-status 这种大小写,经代理的明文那次全变成了 Cf-Ray、Cf-Cache-Status,顺序也变了,直连时 Date 排在第一行,经代理那次除了打头的 Transfer-Encoding,后面十几行全按字母顺序排着,还多出 Keep-Alive: timeout=4 和 Proxy-Connection: keep-alive 两行,直连的回包里没有它们。代理把网站的回复拆开、重写、再发给我,这正是 RFC 9110 给代理下的定义,由客户端自己选定的转发消息的中间人 [3]。明文 HTTP 经过代理,网址、头部、表单,它都能读也能改。
RFC 9110 里还有一个 Via 头部,用来记录消息经过了哪些中间人、避免转发绕圈 [3]。我这次的回包里没有这一行,mihomo 没有加。
第六步回包,哪几行是网站写的,哪几行说明它前面另有一层
状态行 HTTP/1.1 200 OK 之后,直连和经代理收到的头部几乎一样,Server: cloudflare,Age: 3、Age: 7 这样的小数字,cf-cache-status: HIT。这几行说明 example.com 自己前面也站着一台机器,Cloudflare 的边缘节点替它接下了我的请求,并且直接从缓存里回了页面,源站没出面。它对我来说就是反向代理,后面单独说。
经代理那次,页面收完以后 curl 的最后一行是 Connection #0 to host 127.0.0.1:7897 left intact,它保留的连接是到代理的,没有一条是到网站的。页面一样,回来的路不一样。至于快慢,三轮下来直连的总耗时是 247 到 465 毫秒,经代理是 212 到 570 毫秒,最短和最长的一次都出在经代理那边,差别来自缓存和线路抖动,不能拿来说代理更快或更慢,那要看节点,我在机场测评怎么做那页单独测。
第七步留记录,三本账各记了什么
你的这次访问会留在三个地方。网站那头记的是连进来的那个地址,经代理时就是代理出门用的地址。我本来想贴两行不一样的 ip= 给你看,直连一行,经代理一行,结果 Cloudflare 的 trace 接口被我客户端当天的规则判成了直连。两行 ip= 看着确实不同,可经代理那行和我用 curl -4 直连拿到的一字不差,差别只在直连时 curl 自己挑了 IPv6,客户端出门走的是 IPv4。本机客户端坐在中间,每个域名走不走远端节点由它的规则决定,网站记到的是哪个地址,要看那一次它到底把你送去了哪。
代理那头记的东西,可以拿 Squid 这个常见的代理软件当样本。它默认的 access.log 一行十列,时间戳、耗时、客户端地址、结果码和状态码、发回的字节数、请求方法、请求地址、用户名、上游地址、内容类型 [9]。对一次 CONNECT,方法一列写 CONNECT,地址一列只能是你那句 CONNECT 后面带的域名和端口,它只收到了这个,字节数照记,页面内容没有。机场节点用的软件和 Squid 不是一个,它记不记、记多久,没有公开的日志格式可查,我没核到。
你自己的电脑上也有一笔。Windows 把系统代理写在注册表里,我这台机器上 ProxyEnable 是 0,ProxyServer 那一项却还留着 127.0.0.1:7897,多半是客户端关闭系统代理时留下的。命令行工具另有一套,netsh winhttp show proxy 在我这里回的是“直接访问(没有代理服务器)”,和浏览器用的那套设置互不相干。排查代理相关的报错时这两处都要看,具体步骤在代理报错怎么查那页。
反向代理我这次也碰到了,就在第六步的回包里
上面七步里的代理都是正向代理,由客户端选定,替客户端出面去连网站,RFC 9110 的定义是由客户端通过本地配置规则选定的消息转发者 [3]。反向代理站在网站那一边,替网站接请求,RFC 9110 叫它网关,对外表现得就像源站本身 [3]。第六步看到的 Server: cloudflare 就是反向代理露出来的那一行,它替 example.com 挡流量、做缓存,访问者什么都不用设。MDN 把反向代理的用途列成负载均衡、缓存静态内容和压缩 [4]。你配的是正向代理,网站架的是反向代理,一次访问里两种可以同时在场,我这次就是。
家里的路由器为什么不算代理
家里路由器把全家设备的私有地址换成一个公网地址再发出去,这叫 NAT。RFC 3022 描述它的做法是改写每个 IP 包头里的地址,带端口的版本连 TCP 和 UDP 的端口号一起改,对两头的主机来说是透明的,第一个出门的会话发起时绑定地址 [10]。它改的是包头,连接还是从你的电脑直接连到网站,TLS、请求、回包都和路由器无关。代理把你的连接在自己这里结束,再另起一条去网站,两条连接各有各的起止。看 curl 的输出就能分清,我那次直连也是穿过家里路由器出去的,输出里从头到尾没有路由器的影子,Established connection to example.com 写的就是网站。
公司电脑上那条代理地址是谁填的
公司电脑的代理多半不是你填的。Windows 设置里的入口在“网络和 Internet”下的“代理”,微软的说明页写着公司或组织可能要求使用代理服务器,没有信息就去找 IT 部门 [11]。管理员往电脑里下发代理有一套固定的通道,微软文档里叫 NetworkProxy CSP,从 Windows 10 1703 起可用,生效顺序是先自动探测 PAC 脚本,探测不到就用指定的脚本地址,再不行用写死的代理服务器,都没有才直连 [12]。这些项的作用范围是整台设备,另有一个 ProxySettingsPerUser 开关,设成 0 以后代理配置变成全机统一,你在自己的账户里改了也没用 [12]。
浏览器自己另有一套。Edge 的 ProxySettings 策略一旦下发,ProxyMode 这一项就把代理方式定死,用户改不了,文档里写着没有配置这条策略时用户才可以自己选代理 [13]。策略放在注册表 SOFTWARE\Policies\Microsoft\Edge 下面 [13]。改不改得动它,看你的账户有没有管理员权限,该不该改,先问一句 IT,公司的代理往往连着第四步说的 TLS 检查和上网审计,这页不教绕开。
机场节点也是代理服务器,只是站得远
机场订阅给你的每一个节点,都是一台放在境外机房里的代理服务器,差别在于你的电脑和它之间多了一个本机客户端。我 2026 年 6 月到 7 月订阅过的星岛梦(StarDream),当时订阅里有 60 到 70 个节点,协议是 VLESS 和 AnyTLS,客户端收到我那句 CONNECT 以后,把隧道里的字节再包一层协议发给远端节点,节点替我完成第一到第三步,第四步起和网站对话的还是我的电脑。七步被拆到了三台机器上,本机客户端管规则,远端节点管出门,网站只认识出门的那个地址。节点能看见的和上面说的代理一样,域名、时间、字节数,带锁页面的内容它拆不开。
下一次我打算把客户端切到全局模式再跑一遍,看 trace 接口那行 ip= 到底换成了谁的地址。