proxy_demo.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #!/usr/bin/env tsx
  2. /**
  3. * 代理配置演示
  4. * 展示HTTP请求代理功能,包括会话管理和交易所专用代理
  5. */
  6. import { Config } from '../src/config/simpleEnv.js'
  7. import { httpClient, getWithProxy, postWithProxy } from '../src/utils/httpClient.js'
  8. import { installProxyFetch, restoreOriginalFetch } from '../src/utils/proxyFetch.js'
  9. import { logger } from '../src/utils/logger.js'
  10. async function proxyDemo() {
  11. console.log('🌐 HTTP代理配置演示')
  12. console.log('='.repeat(50))
  13. try {
  14. // 1. 显示代理配置状态
  15. console.log('\n📋 第一步: 代理配置状态检查...')
  16. console.log('🔧 全局代理配置:')
  17. console.log(` 启用状态: ${Config.proxy.enabled() ? '✅ 启用' : '❌ 禁用'}`)
  18. if (Config.proxy.enabled()) {
  19. console.log(` 服务器: ${Config.proxy.protocol()}://${Config.proxy.host()}:${Config.proxy.port()}`)
  20. console.log(` 用户名: ${Config.proxy.username() || '未设置'}`)
  21. console.log(` 会话前缀: ${Config.proxy.sessionPrefix() || '未设置'}`)
  22. console.log(` 会话后缀: ${Config.proxy.sessionSuffix() || '未设置'}`)
  23. }
  24. console.log('\n🎯 Aster专用代理配置:')
  25. console.log(` 配置状态: ${Config.proxy.aster.isConfigured() ? '✅ 已配置' : '❌ 未配置'}`)
  26. if (Config.proxy.aster.isConfigured()) {
  27. console.log(
  28. ` 服务器: ${Config.proxy.aster.protocol()}://${Config.proxy.aster.host()}:${Config.proxy.aster.port()}`,
  29. )
  30. console.log(` 用户名: ${Config.proxy.aster.user()}`)
  31. console.log(` 直接密码: ${Config.proxy.aster.pass() ? '已设置' : '未设置'}`)
  32. console.log(` 会话前缀: ${Config.proxy.aster.sessionPrefix() || '未设置'}`)
  33. console.log(` 会话后缀: ${Config.proxy.aster.sessionSuffix() || '未设置'}`)
  34. console.log(` 固定会话: ${Config.proxy.aster.sessionStatic() || '未设置'}`)
  35. // 演示密码构建
  36. const password = Config.proxy.buildPassword('aster')
  37. if (password) {
  38. const maskedPassword = password.substring(0, 8) + '***' + password.substring(password.length - 4)
  39. console.log(` 构建的密码: ${maskedPassword}`)
  40. }
  41. }
  42. // 2. 测试代理URL生成
  43. console.log('\n🔗 第二步: 代理URL生成测试...')
  44. const globalProxyUrl = Config.proxy.getUrl()
  45. const asterProxyUrl = Config.proxy.getUrl('aster')
  46. console.log(`全局代理URL: ${globalProxyUrl ? '已生成 ✅' : '未配置 ❌'}`)
  47. console.log(`Aster代理URL: ${asterProxyUrl ? '已生成 ✅' : '未配置 ❌'}`)
  48. if (Config.isDev()) {
  49. // 开发模式显示更多细节
  50. console.log('\n🔍 详细URL信息:')
  51. if (globalProxyUrl) {
  52. const masked = maskProxyUrl(globalProxyUrl)
  53. console.log(` 全局: ${masked}`)
  54. }
  55. if (asterProxyUrl) {
  56. const masked = maskProxyUrl(asterProxyUrl)
  57. console.log(` Aster: ${masked}`)
  58. }
  59. }
  60. // 3. HTTP客户端测试
  61. console.log('\n🚀 第三步: HTTP客户端代理测试...')
  62. if (Config.proxy.isAnyConfigured()) {
  63. console.log('开始HTTP请求测试 (使用代理)...')
  64. try {
  65. // 测试通用HTTP请求
  66. console.log('\n📡 测试通用GET请求...')
  67. const response1 = await httpClient.get('https://httpbin.org/ip', {
  68. timeout: 10000,
  69. retries: 1,
  70. })
  71. console.log(`✅ 通用请求成功: ${response1.status}`)
  72. if (response1.data?.origin) {
  73. const ip = response1.data.origin
  74. console.log(` 出口IP: ${ip}`)
  75. }
  76. // 测试Aster专用代理请求
  77. if (Config.proxy.aster.isConfigured()) {
  78. console.log('\n🎯 测试Aster专用代理请求...')
  79. const response2 = await httpClient.get('https://httpbin.org/ip', {
  80. exchange: 'aster',
  81. timeout: 10000,
  82. retries: 1,
  83. })
  84. console.log(`✅ Aster专用请求成功: ${response2.status}`)
  85. if (response2.data?.origin) {
  86. const ip = response2.data.origin
  87. console.log(` Aster出口IP: ${ip}`)
  88. }
  89. }
  90. } catch (error: any) {
  91. console.error(`❌ HTTP请求失败: ${error.message}`)
  92. logger.error('代理HTTP请求失败', { error: error.message })
  93. }
  94. } else {
  95. console.log('⚠️ 未配置代理,跳过HTTP测试')
  96. }
  97. // 4. 便捷方法测试
  98. console.log('\n⚡ 第四步: 便捷方法测试...')
  99. if (Config.proxy.isAnyConfigured()) {
  100. try {
  101. console.log('测试便捷GET方法...')
  102. const data = await getWithProxy('https://httpbin.org/json', {
  103. timeout: 10000,
  104. retries: 1,
  105. })
  106. console.log(`✅ 便捷GET成功`)
  107. console.log('测试便捷POST方法...')
  108. const postData = await postWithProxy(
  109. 'https://httpbin.org/post',
  110. { test: 'proxy demo', timestamp: Date.now() },
  111. { timeout: 10000, retries: 1 },
  112. )
  113. console.log(`✅ 便捷POST成功`)
  114. console.log(` 收到数据键: ${Object.keys(postData.json || {}).join(', ')}`)
  115. } catch (error: any) {
  116. console.error(`❌ 便捷方法测试失败: ${error.message}`)
  117. }
  118. }
  119. // 6. 会话管理演示
  120. console.log('\n🎲 第六步: 会话管理演示...')
  121. if (Config.proxy.aster.sessionPrefix() && Config.proxy.aster.sessionSuffix()) {
  122. console.log('演示多个会话ID生成...')
  123. for (let i = 0; i < 3; i++) {
  124. const sessionId = Config.proxy.generateSessionId()
  125. const password = Config.proxy.buildPassword('aster')
  126. console.log(` 会话 ${i + 1}: ${sessionId} -> ${password?.substring(0, 20)}...`)
  127. }
  128. } else {
  129. console.log('未配置会话管理,跳过演示')
  130. }
  131. console.log('\n🎉 代理配置演示完成!')
  132. console.log('\n💡 主要特性:')
  133. console.log(' 🔹 支持全局代理和交易所专用代理')
  134. console.log(' 🔹 高级会话管理 (前缀+随机ID+后缀)')
  135. console.log(' 🔹 自动重试和错误处理')
  136. console.log(' 🔹 完整的代理URL构建')
  137. console.log(' 🔹 兼容原生fetch API')
  138. console.log(' 🔹 详细的请求日志')
  139. } catch (error: any) {
  140. console.error('❌ 代理演示失败:', error)
  141. logger.error('代理演示失败', { error: error.message })
  142. }
  143. }
  144. /**
  145. * 遮蔽代理URL中的敏感信息
  146. */
  147. function maskProxyUrl(url: string): string {
  148. try {
  149. const urlObj = new URL(url)
  150. if (urlObj.username && urlObj.password) {
  151. const maskedUsername = urlObj.username.substring(0, 4) + '***'
  152. const maskedPassword = '***' + urlObj.password.substring(urlObj.password.length - 4)
  153. return `${urlObj.protocol}//${maskedUsername}:${maskedPassword}@${urlObj.host}`
  154. }
  155. return url
  156. } catch {
  157. return url
  158. }
  159. }
  160. /**
  161. * 显示配置帮助
  162. */
  163. function showProxyHelp() {
  164. console.log('\n💡 代理配置说明:')
  165. console.log(`
  166. # 1. 全局代理配置
  167. PROXY_ENABLED=true
  168. PROXY_PROTOCOL=http
  169. PROXY_HOST=proxy.example.com
  170. PROXY_PORT=8080
  171. PROXY_USERNAME=username
  172. PROXY_PASSWORD=password
  173. # 2. 高级会话管理
  174. PROXY_SESSION_PREFIX=prefix_
  175. PROXY_SESSION_SUFFIX=_suffix
  176. PROXY_SESSION_STATIC=fixed123 # 可选,固定会话ID
  177. # 3. Aster专用代理 (优先级更高)
  178. ASTER_PROXY_PROTOCOL=http
  179. ASTER_PROXY_HOST=geo.iproyal.com
  180. ASTER_PROXY_PORT=12321
  181. ASTER_PROXY_USER=tuxla
  182. ASTER_PROXY_PASS=complete_password # 方式一:直接密码
  183. # 或使用会话管理 (方式二)
  184. ASTER_PROXY_SESSION_PREFIX=test123456_country-jp,sg_session-
  185. ASTER_PROXY_SESSION_SUFFIX=_lifetime-59m
  186. ASTER_PROXY_SESSION_STATIC=fixed123 # 可选
  187. # 4. 代码中使用
  188. import { httpClient } from '../src/utils/httpClient'
  189. // 使用全局代理
  190. await httpClient.get('https://api.example.com')
  191. // 使用Aster专用代理
  192. await httpClient.get('https://fapi.asterdex.com/info', { exchange: 'aster' })
  193. `)
  194. }
  195. // 运行演示
  196. if (import.meta.url === `file://${process.argv[1]}`) {
  197. if (process.argv.includes('--help') || process.argv.includes('-h')) {
  198. showProxyHelp()
  199. } else {
  200. proxyDemo()
  201. }
  202. }