fgjohc / src /ProxyPool.js
isididiidid's picture
Upload 7 files
de9786a verified
/**
* 简化的代理池类,支持 HTTP 和 SOCKS5 代理
*/
class ProxyPool {
constructor() {
// 从环境变量读取完整的代理URL
this.proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY || '';
this.isInitialized = false;
// 解析代理URL
this.parseProxyUrl();
}
/**
* 解析代理URL
*/
parseProxyUrl() {
if (!this.proxyUrl) {
console.log('未设置代理URL环境变量 (HTTP_PROXY)');
return;
}
try {
const url = new URL(this.proxyUrl);
this.proxyInfo = {
protocol: url.protocol.replace(':', ''),
host: url.hostname,
port: parseInt(url.port),
username: url.username,
password: url.password,
full: this.proxyUrl
};
console.log(`代理配置解析成功: ${this.proxyInfo.protocol}://${this.proxyInfo.host}:${this.proxyInfo.port}`);
} catch (error) {
console.error(`代理URL解析失败: ${error.message}`);
this.proxyInfo = null;
}
}
/**
* 初始化代理池
*/
async initialize() {
if (this.isInitialized) return true;
if (!this.proxyUrl) {
console.log('未配置代理,将使用直连模式');
this.isInitialized = true;
return true;
}
if (!this.proxyInfo) {
console.error('代理配置无效');
return false;
}
// 测试代理连接
const isValid = await this.testProxyConnection();
if (isValid) {
this.isInitialized = true;
console.log('代理池初始化成功');
return true;
} else {
console.error('代理连接测试失败');
// 即使测试失败,也标记为已初始化,让实际使用时验证
this.isInitialized = true;
console.log('跳过测试失败,继续使用配置的代理');
return true;
}
}
/**
* 测试代理连接
*/
async testProxyConnection() {
if (!this.proxyInfo) return false;
try {
let agent;
// 根据协议选择不同的代理 Agent
if (this.proxyUrl.startsWith('socks5://')) {
const { SocksProxyAgent } = await import('socks-proxy-agent');
agent = new SocksProxyAgent(this.proxyUrl);
console.log('使用 SOCKS5 代理进行测试...');
} else if (this.proxyUrl.startsWith('socks4://')) {
const { SocksProxyAgent } = await import('socks-proxy-agent');
agent = new SocksProxyAgent(this.proxyUrl);
console.log('使用 SOCKS4 代理进行测试...');
} else {
const HttpProxyAgent = (await import('http-proxy-agent')).default;
agent = new HttpProxyAgent(this.proxyUrl);
console.log('使用 HTTP 代理进行测试...');
}
const fetch = (await import('node-fetch')).default;
// 尝试多个测试URL
const testUrls = [
'http://httpbin.org/ip',
'https://api.ipify.org?format=json',
'http://icanhazip.com'
];
for (const testUrl of testUrls) {
try {
console.log(`测试代理连接到: ${testUrl}`);
const response = await fetch(testUrl, {
agent,
timeout: 15000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept': '*/*',
'Connection': 'close'
}
});
if (response.ok) {
const data = await response.text();
let ip = data.trim();
// 尝试解析JSON格式的响应
try {
const jsonData = JSON.parse(data);
ip = jsonData.ip || jsonData.origin || ip;
} catch (e) {
// 如果不是JSON,使用原始文本
}
console.log(`${this.proxyInfo.protocol.toUpperCase()} 代理连接测试成功!`);
console.log(`测试URL: ${testUrl}`);
console.log(`出口IP: ${ip}`);
return true;
} else {
console.log(`测试URL ${testUrl} 失败,状态码: ${response.status}`);
}
} catch (urlError) {
console.log(`测试URL ${testUrl} 出错: ${urlError.message}`);
}
}
console.error('所有测试URL都失败了');
return false;
} catch (error) {
console.error(`代理连接测试失败: ${error.message}`);
return false;
}
}
/**
* 获取代理(每次调用返回相同的代理)
*/
getProxy() {
if (!this.proxyInfo) {
return null;
}
return {
ip: this.proxyInfo.host,
port: this.proxyInfo.port,
protocol: this.proxyInfo.protocol,
full: this.proxyInfo.full
};
}
/**
* 移除代理(记录错误)
*/
removeProxy(ip, port) {
console.log(`记录代理问题: ${ip}:${port}`);
return true;
}
/**
* 获取代理数量
*/
getValidCount() {
return this.proxyInfo ? 1 : 0;
}
/**
* 获取状态信息
*/
getStatus() {
if (!this.proxyInfo) {
return [];
}
return [{
index: 0,
host: this.proxyInfo.host,
port: this.proxyInfo.port,
protocol: this.proxyInfo.protocol,
active: true
}];
}
/**
* 停止代理池
*/
stop() {
console.log('代理池已停止');
}
}
// 导出
export default ProxyPool;
export const proxyPool = new ProxyPool();