#!/usr/bin/env tsx /** * 代理配置演示 * 展示HTTP请求代理功能,包括会话管理和交易所专用代理 */ import { Config } from '../src/config/simpleEnv.js' import { httpClient, getWithProxy, postWithProxy } from '../src/utils/httpClient.js' import { installProxyFetch, restoreOriginalFetch } from '../src/utils/proxyFetch.js' import { logger } from '../src/utils/logger.js' async function proxyDemo() { console.log('🌐 HTTP代理配置演示') console.log('='.repeat(50)) try { // 1. 显示代理配置状态 console.log('\n📋 第一步: 代理配置状态检查...') console.log('🔧 全局代理配置:') console.log(` 启用状态: ${Config.proxy.enabled() ? '✅ 启用' : '❌ 禁用'}`) if (Config.proxy.enabled()) { console.log(` 服务器: ${Config.proxy.protocol()}://${Config.proxy.host()}:${Config.proxy.port()}`) console.log(` 用户名: ${Config.proxy.username() || '未设置'}`) console.log(` 会话前缀: ${Config.proxy.sessionPrefix() || '未设置'}`) console.log(` 会话后缀: ${Config.proxy.sessionSuffix() || '未设置'}`) } console.log('\n🎯 Aster专用代理配置:') console.log(` 配置状态: ${Config.proxy.aster.isConfigured() ? '✅ 已配置' : '❌ 未配置'}`) if (Config.proxy.aster.isConfigured()) { console.log( ` 服务器: ${Config.proxy.aster.protocol()}://${Config.proxy.aster.host()}:${Config.proxy.aster.port()}`, ) console.log(` 用户名: ${Config.proxy.aster.user()}`) console.log(` 直接密码: ${Config.proxy.aster.pass() ? '已设置' : '未设置'}`) console.log(` 会话前缀: ${Config.proxy.aster.sessionPrefix() || '未设置'}`) console.log(` 会话后缀: ${Config.proxy.aster.sessionSuffix() || '未设置'}`) console.log(` 固定会话: ${Config.proxy.aster.sessionStatic() || '未设置'}`) // 演示密码构建 const password = Config.proxy.buildPassword('aster') if (password) { const maskedPassword = password.substring(0, 8) + '***' + password.substring(password.length - 4) console.log(` 构建的密码: ${maskedPassword}`) } } // 2. 测试代理URL生成 console.log('\n🔗 第二步: 代理URL生成测试...') const globalProxyUrl = Config.proxy.getUrl() const asterProxyUrl = Config.proxy.getUrl('aster') console.log(`全局代理URL: ${globalProxyUrl ? '已生成 ✅' : '未配置 ❌'}`) console.log(`Aster代理URL: ${asterProxyUrl ? '已生成 ✅' : '未配置 ❌'}`) if (Config.isDev()) { // 开发模式显示更多细节 console.log('\n🔍 详细URL信息:') if (globalProxyUrl) { const masked = maskProxyUrl(globalProxyUrl) console.log(` 全局: ${masked}`) } if (asterProxyUrl) { const masked = maskProxyUrl(asterProxyUrl) console.log(` Aster: ${masked}`) } } // 3. HTTP客户端测试 console.log('\n🚀 第三步: HTTP客户端代理测试...') if (Config.proxy.isAnyConfigured()) { console.log('开始HTTP请求测试 (使用代理)...') try { // 测试通用HTTP请求 console.log('\n📡 测试通用GET请求...') const response1 = await httpClient.get('https://httpbin.org/ip', { timeout: 10000, retries: 1, }) console.log(`✅ 通用请求成功: ${response1.status}`) if (response1.data?.origin) { const ip = response1.data.origin console.log(` 出口IP: ${ip}`) } // 测试Aster专用代理请求 if (Config.proxy.aster.isConfigured()) { console.log('\n🎯 测试Aster专用代理请求...') const response2 = await httpClient.get('https://httpbin.org/ip', { exchange: 'aster', timeout: 10000, retries: 1, }) console.log(`✅ Aster专用请求成功: ${response2.status}`) if (response2.data?.origin) { const ip = response2.data.origin console.log(` Aster出口IP: ${ip}`) } } } catch (error: any) { console.error(`❌ HTTP请求失败: ${error.message}`) logger.error('代理HTTP请求失败', { error: error.message }) } } else { console.log('⚠️ 未配置代理,跳过HTTP测试') } // 4. 便捷方法测试 console.log('\n⚡ 第四步: 便捷方法测试...') if (Config.proxy.isAnyConfigured()) { try { console.log('测试便捷GET方法...') const data = await getWithProxy('https://httpbin.org/json', { timeout: 10000, retries: 1, }) console.log(`✅ 便捷GET成功`) console.log('测试便捷POST方法...') const postData = await postWithProxy( 'https://httpbin.org/post', { test: 'proxy demo', timestamp: Date.now() }, { timeout: 10000, retries: 1 }, ) console.log(`✅ 便捷POST成功`) console.log(` 收到数据键: ${Object.keys(postData.json || {}).join(', ')}`) } catch (error: any) { console.error(`❌ 便捷方法测试失败: ${error.message}`) } } // 6. 会话管理演示 console.log('\n🎲 第六步: 会话管理演示...') if (Config.proxy.aster.sessionPrefix() && Config.proxy.aster.sessionSuffix()) { console.log('演示多个会话ID生成...') for (let i = 0; i < 3; i++) { const sessionId = Config.proxy.generateSessionId() const password = Config.proxy.buildPassword('aster') console.log(` 会话 ${i + 1}: ${sessionId} -> ${password?.substring(0, 20)}...`) } } else { console.log('未配置会话管理,跳过演示') } console.log('\n🎉 代理配置演示完成!') console.log('\n💡 主要特性:') console.log(' 🔹 支持全局代理和交易所专用代理') console.log(' 🔹 高级会话管理 (前缀+随机ID+后缀)') console.log(' 🔹 自动重试和错误处理') console.log(' 🔹 完整的代理URL构建') console.log(' 🔹 兼容原生fetch API') console.log(' 🔹 详细的请求日志') } catch (error: any) { console.error('❌ 代理演示失败:', error) logger.error('代理演示失败', { error: error.message }) } } /** * 遮蔽代理URL中的敏感信息 */ function maskProxyUrl(url: string): string { try { const urlObj = new URL(url) if (urlObj.username && urlObj.password) { const maskedUsername = urlObj.username.substring(0, 4) + '***' const maskedPassword = '***' + urlObj.password.substring(urlObj.password.length - 4) return `${urlObj.protocol}//${maskedUsername}:${maskedPassword}@${urlObj.host}` } return url } catch { return url } } /** * 显示配置帮助 */ function showProxyHelp() { console.log('\n💡 代理配置说明:') console.log(` # 1. 全局代理配置 PROXY_ENABLED=true PROXY_PROTOCOL=http PROXY_HOST=proxy.example.com PROXY_PORT=8080 PROXY_USERNAME=username PROXY_PASSWORD=password # 2. 高级会话管理 PROXY_SESSION_PREFIX=prefix_ PROXY_SESSION_SUFFIX=_suffix PROXY_SESSION_STATIC=fixed123 # 可选,固定会话ID # 3. Aster专用代理 (优先级更高) ASTER_PROXY_PROTOCOL=http ASTER_PROXY_HOST=geo.iproyal.com ASTER_PROXY_PORT=12321 ASTER_PROXY_USER=tuxla ASTER_PROXY_PASS=complete_password # 方式一:直接密码 # 或使用会话管理 (方式二) ASTER_PROXY_SESSION_PREFIX=test123456_country-jp,sg_session- ASTER_PROXY_SESSION_SUFFIX=_lifetime-59m ASTER_PROXY_SESSION_STATIC=fixed123 # 可选 # 4. 代码中使用 import { httpClient } from '../src/utils/httpClient' // 使用全局代理 await httpClient.get('https://api.example.com') // 使用Aster专用代理 await httpClient.get('https://fapi.asterdex.com/info', { exchange: 'aster' }) `) } // 运行演示 if (import.meta.url === `file://${process.argv[1]}`) { if (process.argv.includes('--help') || process.argv.includes('-h')) { showProxyHelp() } else { proxyDemo() } }