HTTP 代理和 SOCKS5 的区别:原理、工具支持与怎么选
HTTP代理和SOCKS5的区别一次讲清:两种协议怎么工作,SOCKS5代理是什么,socks5 与 socks5h 的 DNS 差异,各工具支持情况,附实测代码和选择建议。
HTTP 代理和 SOCKS5 的区别,在于你的工具用什么“语言”和代理对话。HTTP 代理听得懂网页请求,访问 https 网站时走 CONNECT 隧道;SOCKS5 代理只负责转发任意 TCP 连接,不读取内容。做网页抓取时,两者能访问的网站一样,速度也相近,通常由你的工具支持哪种来决定。
下面依次讲:两种协议在线路上各做了什么,为什么会有 socks5h://,哪些工具支持哪种,以及它们在 ProxyPanda 上怎么用。文中每段代码都连过两个需要登录的本地测试代理:一个 HTTP 代理,一个我们按 RFC 1928 和 RFC 1929 写的 SOCKS5 服务器。测试工具为 curl 8.5、Python requests 2.34 加 PySocks 1.7.1、Node.js 22 加 socks-proxy-agent 10.1、Google Chrome 154 和无头 Chromium 153。
HTTP 代理是什么?
HTTP 代理用 HTTP 和你的工具通信,对两类网站的处理方式不同:
- 访问
http://网站时,工具把整个请求发给代理,由代理去取页面。代理能看到请求内容,也能增删请求头。 - 访问
https://网站时,工具只发一行CONNECT,写明主机和端口。代理连上目标后回复200,之后只负责转发字节。工具通过这条 CONNECT 隧道直接和网站进行 TLS 通信,代理只看得到主机名和字节数,看不到页面内容。
登录信息放在第一个请求的请求头里:
CONNECT api.ipify.org:443 HTTP/1.1
Host: api.ipify.org:443
Proxy-Authorization: Basic VVNFUk5BTUU6UEFTU1dPUkQ=
HTTP/1.1 200 Connection Established
那一长串是 USERNAME:PASSWORD 的 base64 编码,只是换了种写法,并没有加密。curl 和 requests 都会在第一个 CONNECT 里直接带上它,所以我们的测试代理每个连接只记录到一次往返。
SOCKS5 代理是什么?
SOCKS5 代理不认识 HTTP。你让它连哪里,它就建立一条 TCP 连接,然后双向转发字节。所以它也能承载网页以外的流量,比如 SSH 会话,只要程序里有 SOCKS 设置就行。数据开始流动之前,客户端和代理要先完成一次简短的握手:
- 问候。 客户端声明“版本 5”,并列出自己支持的认证方式。
0x00表示无需登录,0x02表示用户名和密码。 - 选择方式。 需要登录的代理会选
0x02。如果客户端没有提供这个选项,代理回复0xFF,即“没有可接受的方式”,然后断开。 - 登录。 按 RFC 1929,客户端以明文字节发送用户名和密码,代理回复成功或失败。
- 连接请求。 客户端用三种地址类型之一指明目标:IPv4 地址、IPv6 地址或域名,再加上端口。
- 回复。 代理连上目标后告知客户端。访问 https 网站时,TLS 随后在这条连接里端到端进行,和 CONNECT 隧道一样。
我们的测试服务器记录了每一步。下面是 requests 使用 socks5h:// 时的日志:
greeting methods=[0, 2]
auth user=USERNAME ok
request cmd=1 atyp=domain target=api.ipify.org:443
SOCKS5 标准里还定义了 UDP 转发。我们没有在自己的网关上验证过,所以请把 ProxyPanda 的 SOCKS5 当作只支持 TCP;如果你的项目要依赖 UDP,请先到 Discord 问一下。
socks5 和 socks5h:DNS 在哪里解析
第 4 步的地址类型最容易让人踩坑。用 socks5h:// 时,工具把主机名发给代理,由代理解析;用 socks5:// 时,你自己的机器先查出 IP,只把 IP 发给代理。只改了一个字母,服务器日志就变成了:
request cmd=1 atyp=ipv4 target=104.26.12.205:443
建议用远程解析的 socks5h,理由有两个。用 socks5:// 时,你的 DNS 服务器以及运营它的人能看到你访问的每一个主机名。另外,大型网站会按地区返回不同的地址,本地解析拿到的是离你近的服务器,而不是离代理出口近的那一台。
HTTP 代理总是远程解析,因为主机名本来就写在请求里。各工具对 SOCKS 的写法不同:
- curl:
socks5h://或--socks5-hostname在代理端解析;socks5://或--socks5在本地解析。 - requests 和 socks-proxy-agent: 规则相同,我们的日志也证实了。
- Chrome: 我们测试时它始终发送主机名,尽管参数写的是
socks5://。 - Firefox: 在连接设置里勾选 SOCKS v5 的 DNS 代理选项(英文界面为“Proxy DNS when using SOCKS v5”)。
哪些工具支持 HTTP,哪些支持 SOCKS5
| 工具 | 带登录的 HTTP 代理 | 带登录的 SOCKS5 代理 |
|---|---|---|
| curl | 内置 | 内置:socks5h:// 或 --socks5-hostname |
| Python requests | 内置 | 需要 pip install "requests[socks]" |
| Node.js | undici 的 ProxyAgent 或 https-proxy-agent |
需要 socks-proxy-agent |
| Chrome 和 Chromium | 支持,靠登录弹窗或 page.authenticate |
不支持,只能用免登录的 |
| Firefox | 支持,靠登录弹窗 | 设置对话框里没有登录字段 |
| 指纹浏览器 | 支持 | GoLogin、Multilogin 和 MoreLogin 的代理表单都列出了 SOCKS5 |
curl
两种写法都可以。第二种把密码从 URL 里拿出来,密码带符号时更省事:
curl -s -x socks5h://USERNAME:PASSWORD@HOST:PORT https://api.ipify.org
curl -s --socks5-hostname HOST:PORT -U "USERNAME:PASSWORD" https://api.ipify.org
密码错误时报 curl: (97) User was rejected by the SOCKS5 server (1 1).,没带登录信息时报 curl: (97) No authentication method was acceptable.。其他报错见代理错误代码,HTTP 那一边的用法见 cURL 教程。
Python requests
requests 要靠 PySocks 才能用 SOCKS。没装的话,socks5h:// 代理会报 InvalidSchema: Missing dependencies for SOCKS support.。先装上扩展:
pip install "requests[socks]"
之后和 Python requests 教程里的 HTTP 写法相比,只有代理 URL 不同:
import requests
PROXY = "socks5h://USERNAME:PASSWORD@HOST:PORT"
proxies = {"http": PROXY, "https": PROXY}
r = requests.get("https://api.ipify.org", proxies=proxies, timeout=30)
print(r.status_code, r.text)
密码错误时会抛出 ConnectionError,信息末尾是 SOCKS5 authentication failed。
Node.js
给 fetch 配代理常用的 undici ProxyAgent 只接受 http: 和 https: 开头的代理 URL。undici 8 新增了 Socks5ProxyAgent,但它会打印实验性警告,也不接受 socks5h:。稳妥的做法是用 socks-proxy-agent(npm i socks-proxy-agent):
import https from 'node:https';
import { SocksProxyAgent } from 'socks-proxy-agent';
const agent = new SocksProxyAgent('socks5h://USERNAME:PASSWORD@HOST:PORT');
https.get('https://api.ipify.org', { agent }, (res) => {
let body = '';
res.on('data', (chunk) => (body += chunk));
res.on('end', () => console.log(res.statusCode, body));
});
用 axios 时,把同一个 agent 按 { httpAgent: agent, httpsAgent: agent, proxy: false } 传进去即可。HTTP 写法见 Node.js 教程。
浏览器:Chrome 无法登录 SOCKS5 代理
我们用 --proxy-server=socks5://HOST:PORT 让 Chrome 154 连接需要登录的 SOCKS5 测试服务器。它在问候阶段只提供了 0x00,即无需登录,服务器因此拒绝,页面报 ERR_SOCKS_CONNECTION_FAILED。把 USERNAME:PASSWORD@ 写进参数,则更早失败,报 ERR_NO_SUPPORTED_PROXIES。无头 Chromium 153 表现相同;给 Playwright 的 SOCKS5 代理设置用户名后,它直接拒绝启动 Chromium:Browser does not support socks5 proxy authentication。同一个 Chrome 通过免登录的 SOCKS5 服务器则能正常打开页面。
Firefox 的连接设置里有 SOCKS 主机、端口和 SOCKS v5 选项,但没有填用户名或密码的地方。所以在浏览器里,要么用带登录的 HTTP,要么把你的地址加进 IP 白名单,免登录使用 SOCKS5。HTTP 的配置步骤见浏览器教程,错误页面的含义见 Chrome 代理错误。
SOCKS5 比 HTTP 快吗?
单看协议,不会有明显差别。连接建立之后,两者都只是转发字节,差别只在建立连接的过程。带登录的 HTTP 代理只需要一次往返:CONNECT 和它的 200。带登录的 SOCKS5 需要三次:问候、登录、连接请求。也就是说,每条新连接多出两次到代理的往返,此后再无差别。
用虚构的数字算一下:如果到代理的一次往返是 40 毫秒,SOCKS5 建立一条连接就多花 80 毫秒。一条连接复用 100 个请求,总共只多 80 毫秒;每个请求都新开连接,100 个请求就多出 8 秒。所以不管用哪种协议,都应该用 keep-alive 复用连接。出口在哪里、网站响应快不快,影响要大得多。
SOCKS5 和 HTTPS 代理
“HTTPS 代理”有两种意思:
- 代理 URL 里写
https://,表示和代理本身建立加密连接。你到代理这一段,登录信息和CONNECT行都被加密。 - 工具协议菜单里的“HTTPS”,常常指能建立 CONNECT 隧道的 HTTP 代理。Proxifier 就是这么用的,Proxifier 教程里有说明。
普通 HTTP 和 SOCKS5 都不加密你到代理这一段:HTTP 的登录信息是 base64,SOCKS5 的登录信息是明文字节。访问 https 网站时,页面内容在任何情况下都是端到端加密的。在不可信的网络上,IP 白名单可以让密码根本不出现在线路上;代理还能隐藏什么、不能隐藏什么,见代理和 VPN 的区别。
什么时候用 HTTP,什么时候用 SOCKS5
- 用 curl、requests 或 Node 抓取 https 网站: 用 HTTP。不用额外安装,出错时返回 407、502 这类状态码,比一个直接断开的连接好排查。
- 不是网页客户端的程序, 或者只提供 SOCKS 设置的程序:用 SOCKS5。
- Chrome 或 Firefox: 用带登录的 HTTP,或者加了 IP 白名单的 SOCKS5。
- 指纹浏览器: 两种都行,选它的表单和你的服务页面都对得上的那种。
HTTP 和 SOCKS5 在 ProxyPanda 上怎么用
住宅代理的网关在它公布的每个端口上都同时支持 HTTP 和 SOCKS5。服务页面上的 HOST、PORT、USERNAME 和 PASSWORD 保持不变,只换协议头:http:// 或 socks5h://。选了 Sticky IP 时,会话选项附在密码里,所以不管用哪种协议头,都请按页面显示原样复制。
ISP 和数据中心代理,每个代理都有一个可以在控制台切换的协议:HTTP、HTTPS 或 SOCKS5,以该代理提供的为准。有的代理会为 SOCKS5 单独显示一个端口,服务页面显示的是所选协议对应的端口,所以切换之后请重新复制端口。
IP 白名单对两种协议都有效,也是在 Chrome 里使用 SOCKS5 的办法。
常见问题
HTTP 代理和 SOCKS5 有什么区别? HTTP 代理说 HTTP,用 CONNECT 为 https 建立隧道。SOCKS5 代理经过一次简短握手后转发任意 TCP 连接,从不读取流量内容。
socks5h 是什么意思? 协议还是 SOCKS5,只是把主机名交给代理去解析。做抓取时建议用它。
SOCKS5 比 HTTP 更安全吗? 不会。两者都不加密你到代理这一段。https 网站的内容走哪一种都是端到端加密的。
Chrome 为什么报 ERR_SOCKS_CONNECTION_FAILED? 要么这个 SOCKS5 代理需要登录,而 Chrome 发不了登录信息;要么这个端口只支持 HTTP。把你的 IP 加进白名单,或者把代理设置改成 http://。
下一步
在住宅代理服务上,用上面的 curl 命令对同一个端口各跑一次:一次用 http://,一次用 socks5h://。两次都应该打印一个不是你自己的出口地址;哪种更适合你的工具,就留哪种。这个测试用一笔小额充值就够了;如果其中一种连不上,请带上报错信息、遮住密码,到 Discord 提问。