quickstart.md 24 KB

快速开始:通用HTTP客户端多平台账户管理

版本: 1.0.0 创建日期: 2025-09-28 目标: 提供HTTP客户端库的快速开始指南和使用示例

15分钟快速开始

步骤1: 安装和配置

# 安装HTTP客户端库
npm install @yourorg/http-client

# 安装依赖(如果单独使用)
npm install @yourorg/credential-manager winston https-proxy-agent

步骤2: 环境配置

创建 .env 文件:

# Pacifica DEX配置
PACIFICA_ACCOUNT_ID=your_pacifica_account
PACIFICA_PRIVATE_KEY=your_pacifica_private_key

# Aster DEX配置
ASTER_ACCOUNT_ID=0x_your_aster_account
ASTER_PRIVATE_KEY=0x_your_aster_private_key

# Binance配置
BINANCE_API_KEY=your_binance_api_key
BINANCE_SECRET_KEY=your_binance_secret_key

# 可选:代理配置
HTTP_PROXY_URL=http://username:password@proxy.server.com:8080

步骤3: 基本使用

import { UniversalHttpClient } from '@yourorg/http-client'

// 创建客户端实例
const httpClient = new UniversalHttpClient({
  timeout: {
    connect: 5000,
    read: 30000,
    write: 15000
  },
  retry: {
    maxAttempts: 3,
    exponentialBackoff: true
  },
  enableLogging: true
})

// 添加账户
await httpClient.addAccount('pacifica', 'main-account', {
  accountId: process.env.PACIFICA_ACCOUNT_ID!,
  privateKey: process.env.PACIFICA_PRIVATE_KEY!
})

// 发起API请求
const response = await httpClient.request({
  platform: 'pacifica',
  accountId: 'main-account',
  method: 'GET',
  url: '/api/v1/account/info'
})

console.log('账户信息:', response.data)

完整使用场景

场景1: 多平台账户余额查询

目标: 查询所有平台账户的余额信息

import { UniversalHttpClient } from '@yourorg/http-client'

async function queryAllBalances() {
  const client = new UniversalHttpClient()

  // 配置多个平台账户
  await client.addAccount('pacifica', 'pac-main', {
    accountId: process.env.PACIFICA_ACCOUNT_ID!,
    privateKey: process.env.PACIFICA_PRIVATE_KEY!
  })

  await client.addAccount('aster', 'ast-main', {
    accountId: process.env.ASTER_ACCOUNT_ID!,
    privateKey: process.env.ASTER_PRIVATE_KEY!
  })

  await client.addAccount('binance', 'bnc-main', {
    apiKey: process.env.BINANCE_API_KEY!,
    secretKey: process.env.BINANCE_SECRET_KEY!
  })

  // 并发查询所有平台余额
  const requests = [
    {
      platform: 'pacifica' as const,
      accountId: 'pac-main',
      method: 'GET' as const,
      url: '/api/v1/account/info'
    },
    {
      platform: 'aster' as const,
      accountId: 'ast-main',
      method: 'GET' as const,
      url: '/api/v1/account/balance'
    },
    {
      platform: 'binance' as const,
      accountId: 'bnc-main',
      method: 'GET' as const,
      url: '/api/v3/account'
    }
  ]

  // 批量执行请求
  const responses = await client.batchRequest(requests)

  // 处理结果
  responses.forEach((response, index) => {
    const platform = requests[index].platform
    console.log(`${platform} 余额:`, response.data)
  })

  await client.close()
}

// 运行示例
queryAllBalances().catch(console.error)

预期输出:

pacifica 余额: { totalBalance: 1500.50, availableBalance: 1200.30, ... }
aster 余额: { balance: 2300.75, lockedBalance: 100.25, ... }
binance 余额: { balances: [{ asset: 'USDT', free: '1000.00', ... }] }

场景2: 平台特定订单下单

目标: 在不同平台下单,处理平台特定的认证和格式要求

import { UniversalHttpClient } from '@yourorg/http-client'

async function placeOrdersAcrossPlatforms() {
  const client = new UniversalHttpClient({
    retry: {
      maxAttempts: 3,
      shouldRetry: (error) => {
        // 认证错误不重试,网络错误重试
        return error.code !== 'AUTH_FAILED'
      }
    }
  })

  // 添加账户
  await client.addAccount('pacifica', 'trading', {
    accountId: process.env.PACIFICA_ACCOUNT_ID!,
    privateKey: process.env.PACIFICA_PRIVATE_KEY!
  })

  await client.addAccount('aster', 'trading', {
    accountId: process.env.ASTER_ACCOUNT_ID!,
    privateKey: process.env.ASTER_PRIVATE_KEY!
  })

  try {
    // Pacifica 限价单
    const pacificaOrder = await client.request({
      platform: 'pacifica',
      accountId: 'trading',
      method: 'POST',
      url: '/api/v1/order/limit',
      body: {
        symbol: 'BTC-USD',
        side: 'buy',
        amount: 0.001,
        price: 65000,
        timeInForce: 'GTC'
      },
      options: {
        timeout: { read: 10000 },
        idempotencyKey: `pac-order-${Date.now()}`
      }
    })

    console.log('Pacifica订单成功:', pacificaOrder.data.orderId)

    // Aster 市价单
    const asterOrder = await client.request({
      platform: 'aster',
      accountId: 'trading',
      method: 'POST',
      url: '/api/v1/orders',
      body: {
        symbol: 'BTCUSDT',
        side: 'BUY',
        type: 'MARKET',
        quantity: 0.001
      },
      options: {
        timeout: { read: 15000 },
        idempotencyKey: `ast-order-${Date.now()}`
      }
    })

    console.log('Aster订单成功:', asterOrder.data.orderId)

  } catch (error) {
    if (error.code === 'AUTH_FAILED') {
      console.error('认证失败,请检查凭据配置')
    } else if (error.code === 'RATE_LIMITED') {
      console.error('触发速率限制,请稍后重试')
    } else {
      console.error('订单失败:', error.message)
    }
  }

  await client.close()
}

placeOrdersAcrossPlatforms().catch(console.error)

场景3: 代理开关和高级配置

目标: 灵活控制代理开关,使用高级代理配置进行网络隔离

import { UniversalHttpClient } from '@yourorg/http-client'

async function proxyAdvancedConfiguration() {
  const client = new UniversalHttpClient({
    // 全局代理配置
    globalProxy: {
      enabled: true,
      url: process.env.HTTP_PROXY_URL,
      type: 'http',
      auth: {
        username: process.env.PROXY_USERNAME!,
        password: process.env.PROXY_PASSWORD!
      },
      pool: {
        servers: [
          'http://proxy1.example.com:8080',
          'http://proxy2.example.com:8080',
          'http://proxy3.example.com:8080'
        ],
        strategy: 'round-robin',
        healthCheckUrl: 'http://httpbin.org/ip',
        healthCheckInterval: 60000
      },
      failover: {
        enabled: true,
        maxRetries: 3,
        delay: 1000,
        fallbackToDirect: false // 不允许直连回退
      }
    }
  })

  // 添加账户(使用全局代理)
  await client.addAccount('pacifica', 'global-proxy-account', {
    accountId: process.env.PACIFICA_ACCOUNT_ID!,
    privateKey: process.env.PACIFICA_PRIVATE_KEY!
  })

  // 添加账户(禁用代理)
  await client.addAccount('aster', 'no-proxy-account', {
    accountId: process.env.ASTER_ACCOUNT_ID!,
    privateKey: process.env.ASTER_PRIVATE_KEY!,
    proxyDisabled: true // 账户级别禁用代理
  })

  try {
    console.log('=== 代理开关测试 ===')

    // 1. 使用全局代理(默认行为)
    console.log('\\n1. 使用全局代理配置:')
    const response1 = await client.request({
      platform: 'pacifica',
      accountId: 'global-proxy-account',
      method: 'GET',
      url: '/api/v1/market/prices',
      options: {
        proxy: { strategy: 'global' } // 明确使用全局代理
      }
    })
    console.log('- 响应时间:', response1.metadata.duration, 'ms')
    console.log('- 使用代理:', response1.metadata.usedProxy)

    // 2. 强制使用特定代理
    console.log('\\n2. 强制使用特定代理:')
    const response2 = await client.request({
      platform: 'pacifica',
      accountId: 'global-proxy-account',
      method: 'GET',
      url: '/api/v1/account/info',
      options: {
        proxy: {
          strategy: 'force',
          forceProxy: {
            enabled: true,
            url: 'http://special-proxy.example.com:8080',
            type: 'http',
            auth: {
              username: 'special-user',
              password: 'special-pass'
            },
            session: {
              prefix: 'force-session-',
              suffix: '_custom',
              rotation: false,
              sticky: true
            }
          }
        }
      }
    })
    console.log('- 使用的代理:', response2.metadata.proxyUsed)

    // 3. 临时禁用代理
    console.log('\\n3. 临时禁用代理(直连):')
    const response3 = await client.request({
      platform: 'pacifica',
      accountId: 'global-proxy-account',
      method: 'GET',
      url: '/api/v1/market/tickers',
      options: {
        proxy: {
          strategy: 'disabled',
          disableProxy: true
        }
      }
    })
    console.log('- 使用代理:', response3.metadata.usedProxy)
    console.log('- 直连响应时间:', response3.metadata.duration, 'ms')

    // 4. 账户级别禁用代理的测试
    console.log('\\n4. 账户级别禁用代理:')
    const response4 = await client.request({
      platform: 'aster',
      accountId: 'no-proxy-account',
      method: 'GET',
      url: '/api/v1/market/tickers'
      // 即使不指定proxy选项,该账户也不会使用代理
    })
    console.log('- 使用代理:', response4.metadata.usedProxy)

    // 5. 代理轮换测试
    console.log('\\n5. 代理轮换测试:')
    for (let i = 0; i < 3; i++) {
      const response = await client.request({
        platform: 'pacifica',
        accountId: 'global-proxy-account',
        method: 'GET',
        url: '/api/v1/market/prices',
        options: {
          proxy: {
            strategy: 'global',
            rotation: {
              enabled: true,
              interval: 1, // 每次请求轮换
              strategy: 'round-robin'
            }
          }
        }
      })
      console.log(`- 第${i+1}次请求代理:`, response.metadata.proxyUsed)
    }

    // 6. 代理健康检查
    console.log('\\n6. 代理健康检查:')
    const proxyStatus = await client.getProxyStatus()
    console.log('代理池状态:', {
      总代理数: proxyStatus.pool?.totalProxies,
      活跃代理数: proxyStatus.pool?.activeProxies,
      当前代理: proxyStatus.currentProxy,
      健康状态: proxyStatus.health.isHealthy,
      连续失败次数: proxyStatus.health.consecutiveFailures
    })

    // 7. 代理故障转移测试
    console.log('\\n7. 代理故障转移测试:')
    const response7 = await client.request({
      platform: 'pacifica',
      accountId: 'global-proxy-account',
      method: 'GET',
      url: '/api/v1/market/depth',
      params: { symbol: 'BTC-USD' },
      options: {
        proxy: {
          strategy: 'global',
          healthCheck: {
            enabled: true,
            timeout: 2000,
            failureThreshold: 2
          }
        },
        retry: {
          maxAttempts: 5, // 增加重试次数以测试故障转移
          shouldRetry: (error) => {
            return error.code === 'PROXY_ERROR' || error.code === 'TIMEOUT'
          }
        }
      }
    })
    console.log('- 故障转移成功,响应:', response7.status)

  } catch (error) {
    console.error('代理配置错误:', {
      code: error.code,
      message: error.message,
      proxyStatus: error.proxyStatus
    })

    // 代理错误处理
    if (error.code === 'PROXY_ERROR') {
      console.log('\\n尝试切换到备用代理或直连...')
      const fallbackResponse = await client.request({
        platform: 'pacifica',
        accountId: 'global-proxy-account',
        method: 'GET',
        url: '/api/v1/market/prices',
        options: {
          proxy: { strategy: 'disabled' } // 回退到直连
        }
      })
      console.log('直连回退成功:', fallbackResponse.status)
    }
  }

  await client.close()
}

proxyAdvancedConfiguration().catch(console.error)

场景4: 性能监控和健康检查

目标: 监控客户端性能,确保服务质量

import { UniversalHttpClient } from '@yourorg/http-client'

async function performanceMonitoring() {
  const client = new UniversalHttpClient({
    metrics: {
      enabled: true,
      collectInterval: 30000, // 30秒收集一次指标
      historyRetention: 3600000 // 保留1小时历史
    }
  })

  // 添加多个账户进行测试
  await client.addAccount('pacifica', 'test-1', {
    accountId: process.env.PACIFICA_ACCOUNT_ID!,
    privateKey: process.env.PACIFICA_PRIVATE_KEY!
  })

  await client.addAccount('aster', 'test-2', {
    accountId: process.env.ASTER_ACCOUNT_ID!,
    privateKey: process.env.ASTER_PRIVATE_KEY!
  })

  // 模拟高并发请求
  console.log('开始性能测试...')
  const startTime = Date.now()

  const requests = Array.from({ length: 100 }, (_, i) => ({
    platform: i % 2 === 0 ? 'pacifica' as const : 'aster' as const,
    accountId: i % 2 === 0 ? 'test-1' : 'test-2',
    method: 'GET' as const,
    url: i % 2 === 0 ? '/api/v1/market/prices' : '/api/v1/market/tickers'
  }))

  try {
    // 批量执行并发请求
    const responses = await client.batchRequest(requests)
    const endTime = Date.now()

    console.log('性能测试完成:', {
      totalRequests: requests.length,
      successfulRequests: responses.filter(r => r.ok).length,
      totalTime: endTime - startTime,
      averageTime: (endTime - startTime) / requests.length
    })

    // 获取详细健康状态
    const health = await client.getHealth()
    console.log('系统健康状态:', {
      status: health.status,
      platforms: Object.entries(health.platforms).map(([name, status]) => ({
        platform: name,
        status: status.status,
        responseTime: status.responseTime,
        successRate: status.successRate
      })),
      metrics: {
        totalRequests: health.metrics.totalRequests,
        successRate: health.metrics.successfulRequests / health.metrics.totalRequests,
        averageResponseTime: health.metrics.averageResponseTime,
        p99ResponseTime: health.metrics.p99ResponseTime,
        activeConnections: health.metrics.activeConnections
      }
    })

  } catch (error) {
    console.error('性能测试失败:', error)
  }

  await client.close()
}

performanceMonitoring().catch(console.error)

测试验证

单元测试示例

import { UniversalHttpClient } from '@yourorg/http-client'
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals'

describe('UniversalHttpClient', () => {
  let client: UniversalHttpClient

  beforeEach(async () => {
    client = new UniversalHttpClient({
      timeout: { connect: 1000, read: 5000, write: 3000 }
    })
  })

  afterEach(async () => {
    await client.close()
  })

  it('应该成功添加Pacifica账户', async () => {
    await client.addAccount('pacifica', 'test-account', {
      accountId: 'test-account-id',
      privateKey: 'test-private-key'
    })

    const health = await client.getHealth()
    expect(health.platforms.pacifica).toBeDefined()
  })

  it('应该处理认证失败错误', async () => {
    await client.addAccount('pacifica', 'invalid-account', {
      accountId: 'invalid',
      privateKey: 'invalid'
    })

    await expect(client.request({
      platform: 'pacifica',
      accountId: 'invalid-account',
      method: 'GET',
      url: '/api/v1/account/info'
    })).rejects.toThrow('AUTH_FAILED')
  })

  it('应该在速率限制时正确重试', async () => {
    // 测试重试逻辑
    // 实现省略...
  })
})

集成测试示例

# 运行完整集成测试
npm run test:integration

# 运行特定平台测试
npm run test:pacifica
npm run test:aster
npm run test:binance

# 运行性能基准测试
npm run test:performance

代理开关最佳实践

代理策略选择指南

// 1. 全局代理策略(推荐用于生产环境)
const productionConfig = {
  proxy: { strategy: 'global' },  // 使用全局配置的代理池
}

// 2. 账户专用代理策略(推荐用于多账户隔离)
const accountConfig = {
  proxy: { strategy: 'account' }, // 使用账户专用代理配置
}

// 3. 强制代理策略(推荐用于特殊需求)
const forceConfig = {
  proxy: {
    strategy: 'force',
    forceProxy: {
      enabled: true,
      url: 'http://special.proxy.com:8080',
      type: 'socks5'
    }
  }
}

// 4. 禁用代理策略(推荐用于调试和测试)
const directConfig = {
  proxy: { strategy: 'disabled' }
}

代理开关环境变量配置

# .env文件配置示例

# 全局代理配置
GLOBAL_PROXY_ENABLED=true
GLOBAL_PROXY_URL=http://proxy.example.com:8080
GLOBAL_PROXY_USERNAME=your_username
GLOBAL_PROXY_PASSWORD=your_password

# 代理池配置
PROXY_POOL_SERVERS=http://proxy1.com:8080,http://proxy2.com:8080,http://proxy3.com:8080
PROXY_POOL_STRATEGY=round-robin
PROXY_HEALTH_CHECK_URL=http://httpbin.org/ip
PROXY_HEALTH_CHECK_INTERVAL=60000

# 账户专用代理配置
PACIFICA_PROXY_ENABLED=true
PACIFICA_PROXY_URL=http://pacifica-proxy.com:8080
PACIFICA_PROXY_SESSION_PREFIX=pac_session_

ASTER_PROXY_ENABLED=false  # 禁用Aster账户代理
BINANCE_PROXY_ENABLED=true
BINANCE_PROXY_URL=http://binance-proxy.com:8080

# 故障转移配置
PROXY_FAILOVER_ENABLED=true
PROXY_FAILOVER_MAX_RETRIES=3
PROXY_FAILOVER_DELAY=1000
PROXY_FALLBACK_TO_DIRECT=false  # 是否允许直连回退

代理开关使用模式

import { UniversalHttpClient } from '@yourorg/http-client'

// 模式1: 智能代理开关(推荐)
async function smartProxyUsage() {
  const client = new UniversalHttpClient({
    globalProxy: {
      enabled: process.env.GLOBAL_PROXY_ENABLED === 'true',
      url: process.env.GLOBAL_PROXY_URL,
      // 自动故障转移和健康检查
      failover: { enabled: true, fallbackToDirect: false },
      pool: { strategy: 'fastest' }
    }
  })

  // 根据操作类型智能选择代理策略
  const marketDataResponse = await client.request({
    platform: 'pacifica',
    accountId: 'main',
    method: 'GET',
    url: '/api/v1/market/prices',
    options: {
      proxy: {
        strategy: 'global',  // 市场数据使用全局代理池
        rotation: { enabled: true }
      }
    }
  })

  const accountResponse = await client.request({
    platform: 'pacifica',
    accountId: 'main',
    method: 'GET',
    url: '/api/v1/account/info',
    options: {
      proxy: {
        strategy: 'account',  // 账户数据使用专用代理
        healthCheck: { enabled: true }
      }
    }
  })

  const tradingResponse = await client.request({
    platform: 'pacifica',
    accountId: 'main',
    method: 'POST',
    url: '/api/v1/order/limit',
    body: { symbol: 'BTC-USD', side: 'buy', amount: 0.001 },
    options: {
      proxy: {
        strategy: 'force',  // 交易操作使用稳定代理
        forceProxy: {
          enabled: true,
          url: process.env.TRADING_PROXY_URL,
          connection: { keepAlive: true, timeout: 10000 }
        }
      }
    }
  })
}

// 模式2: 条件代理开关
async function conditionalProxyUsage() {
  const client = new UniversalHttpClient()

  // 根据环境条件动态选择代理策略
  const isDevelopment = process.env.NODE_ENV === 'development'
  const isHighLatency = await checkNetworkLatency() > 200

  const proxyStrategy = isDevelopment
    ? 'disabled'  // 开发环境直连
    : isHighLatency
    ? 'force'     // 高延迟强制代理
    : 'global'    // 正常情况全局代理

  const response = await client.request({
    platform: 'pacifica',
    accountId: 'main',
    method: 'GET',
    url: '/api/v1/market/depth',
    options: { proxy: { strategy: proxyStrategy } }
  })
}

// 模式3: 代理性能监控和自动切换
async function performanceBasedProxyUsage() {
  const client = new UniversalHttpClient({
    globalProxy: {
      enabled: true,
      pool: {
        servers: ['http://fast-proxy.com:8080', 'http://stable-proxy.com:8080'],
        strategy: 'fastest',  // 自动选择最快代理
        healthCheckInterval: 30000
      }
    }
  })

  // 性能监控和自动切换
  for (let i = 0; i < 10; i++) {
    const startTime = Date.now()

    try {
      const response = await client.request({
        platform: 'pacifica',
        accountId: 'main',
        method: 'GET',
        url: '/api/v1/market/prices',
        options: {
          proxy: {
            strategy: 'global',
            rotation: { enabled: true, strategy: 'fastest' }
          }
        }
      })

      const duration = Date.now() - startTime
      console.log(`请求${i+1}: ${duration}ms, 代理: ${response.metadata.proxyUsed}`)

      // 如果响应时间过长,切换到直连
      if (duration > 1000) {
        console.log('代理响应过慢,切换到直连模式')
        break
      }

    } catch (error) {
      if (error.code === 'PROXY_ERROR') {
        console.log('代理故障,自动切换到备用代理')
        // 客户端会自动切换到备用代理
      }
    }
  }
}

async function checkNetworkLatency(): Promise<number> {
  // 简单的延迟检测实现
  const start = Date.now()
  try {
    await fetch('http://httpbin.org/delay/0')
    return Date.now() - start
  } catch {
    return 9999 // 网络不可达
  }
}

代理开关调试技巧

// 启用详细的代理日志
const client = new UniversalHttpClient({
  logging: {
    level: 'debug',
    proxyDetails: true  // 记录代理连接详细信息
  }
})

// 监听代理事件
client.on('proxy:connect', (proxyUrl) => {
  console.log(`代理连接成功: ${proxyUrl}`)
})

client.on('proxy:disconnect', (proxyUrl, reason) => {
  console.log(`代理断开连接: ${proxyUrl}, 原因: ${reason}`)
})

client.on('proxy:error', (proxyUrl, error) => {
  console.error(`代理错误: ${proxyUrl}`, error)
})

client.on('proxy:switch', (fromProxy, toProxy) => {
  console.log(`代理切换: ${fromProxy} -> ${toProxy}`)
})

// 代理状态实时监控
setInterval(async () => {
  const status = await client.getProxyStatus()
  console.log('代理状态监控:', {
    当前代理: status.currentProxy,
    连接状态: status.status,
    成功率: `${(status.stats.successfulRequests / status.stats.totalRequests * 100).toFixed(1)}%`,
    平均响应时间: `${status.stats.averageResponseTime}ms`,
    健康状态: status.health.isHealthy ? '健康' : '异常'
  })
}, 30000)

故障排除

常见问题

  1. 认证失败 (AUTH_FAILED)

    错误: 签名验证失败
    解决: 检查私钥格式和账户ID是否正确
    
  2. 连接超时 (TIMEOUT)

    错误: 请求超时
    解决: 检查网络连接,调整超时配置
    
  3. 速率限制 (RATE_LIMITED)

    错误: 超出API调用限制
    解决: 增加请求间隔,实现退避重试
    
  4. 代理连接失败

    错误: 代理服务器无响应
    解决: 验证代理配置,检查防火墙设置
    

调试技巧

// 启用详细日志
const client = new UniversalHttpClient({
  logging: {
    level: 'debug',
    sensitiveData: true
  }
})

// 查看请求详情
client.on('request', (request) => {
  console.log('发送请求:', request.id, request.url)
})

client.on('response', (response) => {
  console.log('收到响应:', response.requestId, response.status)
})

client.on('error', (error) => {
  console.error('请求错误:', error.code, error.message)
})

生产部署建议

配置优化

// 生产环境配置
const productionConfig = {
  timeout: {
    connect: 5000,
    read: 30000,
    write: 15000
  },
  retry: {
    maxAttempts: 3,
    exponentialBackoff: true,
    delay: 1000
  },
  connectionPool: {
    maxConnectionsPerPlatform: 20,
    idleTimeout: 30000,
    reuseConnections: true
  },
  logging: {
    level: 'info',
    sensitiveData: false, // 生产环境不记录敏感数据
    retention: '30d'
  }
}

监控设置

// 设置监控告警
client.on('healthChange', (health) => {
  if (health.status === 'unhealthy') {
    // 发送告警通知
    alertingService.sendAlert('HTTP客户端健康状态异常')
  }
})

// 性能监控
setInterval(async () => {
  const metrics = await client.getPerformanceMetrics()
  if (metrics.averageResponseTime > 100) {
    console.warn('响应时间超出目标值')
  }
}, 60000)

快速开始总结: 通过以上示例,您可以在15分钟内完成HTTP客户端的基本配置,在1小时内掌握高级功能使用。