You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用AnyEvent::HTTP通过Socks代理并行发送HTTP GET请求

解决AnyEvent并行HTTP请求通过SOCKS代理的问题

嘿,我之前刚好折腾过类似的场景!AnyEvent自带的HTTP客户端(AnyEvent::HTTP)默认确实只支持HTTP/HTTPS代理,没法直接用SOCKS,但咱们有两种靠谱的办法绕开这个限制,亲测都能正常对接Tor的localhost:9050代理:

方案一:用AnyEvent::Socket::Socks扩展AnyEvent::HTTP

这个方案是给AnyEvent::HTTP加上SOCKS代理的底层支持,核心是用AnyEvent::Socket::Socks模块替换默认的TCP连接逻辑。

首先得安装依赖模块:

cpanm AnyEvent::Socket::Socks

然后是并行请求的示例代码:

use strict;
use warnings;
use AnyEvent;
use AnyEvent::HTTP;
use AnyEvent::Socket::Socks;

# 配置SOCKS代理信息(Tor默认配置)
my $socks_host = 'localhost';
my $socks_port = 9050;

# 待请求的URL列表
my @urls = (
    'https://check.torproject.org/api/ip',
    'https://example.com',
    'https://httpbin.org/ip'
);

# 创建事件循环控制器
my $cv = AnyEvent->condvar;

foreach my $url (@urls) {
    $cv->begin;
    
    http_request
        GET => $url,
        # 自定义连接逻辑:先通过SOCKS代理握手再转发请求
        connect => sub {
            my ($target_host, $target_port, $connect_cb) = @_;
            # 先连接SOCKS代理服务器
            tcp_connect $socks_host, $socks_port, sub {
                my ($fh) = @_;
                unless ($fh) {
                    $connect_cb->(); # 连接失败时传递空句柄
                    return;
                }
                # 发起SOCKS5握手,指定目标网站的地址
                socks_handshake $fh, {
                    host => $target_host,
                    port => $target_port,
                    version => 5,
                }, sub {
                    my ($err) = @_;
                    if ($err) {
                        warn "SOCKS握手失败 ($url): $err";
                        close $fh;
                        $connect_cb->();
                    } else {
                        $connect_cb->($fh); # 握手成功,传递可用句柄
                    }
                };
            };
        },
        sub {
            my ($body, $hdr) = @_;
            if ($hdr->{Status} =~ /^2/) {
                print "请求成功 ($url):\n$body\n\n";
            } else {
                warn "请求失败 ($url): 状态码 $hdr->{Status}, 原因 $hdr->{Reason}\n";
            }
            $cv->end;
        };
}

# 等待所有请求完成
$cv->recv;

这段代码的核心是通过connect参数,把原本直接连接目标网站的逻辑,改成先连接SOCKS代理、完成握手后再转发请求。

方案二:用AnyEvent::Curl::Multi封装curl

如果觉得底层逻辑有点繁琐,咱们可以直接用AnyEvent::Curl::Multi——它封装了curl的多请求功能,而curl本身对SOCKS代理的支持非常完善,这样就能直接复用curl的能力了。

先安装依赖:

cpanm AnyEvent::Curl::Multi

示例代码如下:

use strict;
use warnings;
use AnyEvent;
use AnyEvent::Curl::Multi;

# 配置SOCKS5代理(Tor默认地址)
my $proxy = 'socks5://localhost:9050';

# 待请求的URL列表
my @urls = (
    'https://check.torproject.org/api/ip',
    'https://example.com',
    'https://httpbin.org/ip'
);

# 创建curl多请求实例
my $curl_multi = AnyEvent::Curl::Multi->new;

# 创建事件循环控制器
my $cv = AnyEvent->condvar;

foreach my $url (@urls) {
    $cv->begin;
    
    $curl_multi->add(
        {
            url => $url,
            # 设置curl的SOCKS代理选项
            opts => {
                CURLOPT_PROXY => $proxy,
                CURLOPT_PROXYTYPE => 7, # 数值7对应CURLPROXY_SOCKS5
                CURLOPT_FOLLOWLOCATION => 1, # 自动处理跳转
                CURLOPT_SSL_VERIFYPEER => 0, # 测试Tor时可临时关闭证书验证(可选)
            },
            cb => sub {
                my ($response, $stats) = @_;
                if ($response->{code} =~ /^2/) {
                    print "请求成功 ($url):\n$response->{body}\n\n";
                } else {
                    warn "请求失败 ($url): 状态码 $response->{code}, 原因 $response->{message}\n";
                }
                $cv->end;
            }
        }
    );
}

# 启动请求并等待全部完成
$curl_multi->start;
$cv->recv;

这个方案更省心,curl已经帮我们处理了所有SOCKS的细节,只需要设置对应的选项就行。如果需要带认证的SOCKS5代理,直接把proxy字符串改成socks5://用户名:密码@host:port即可。

验证是否生效

不管用哪种方案,都可以请求https://check.torproject.org/api/ip来验证:返回的IP应该是Tor出口节点的IP,而不是你的真实IP。

内容的提问来源于stack exchange,提问作者Derek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:21:33