欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit仓库地址: https://atomgit.com/yty-/http_error

问题:
在这里插入图片描述
还原问题:

在这里插入图片描述
解决问题:
在这里插入图片描述

一、问题背景

在 HarmonyOS 应用开发中,网络连接是最基础也是最关键的功能之一。当应用尝试与服务器建立 TCP 连接时,如果连接失败,就会触发错误码 2300007

无法连接到服务器是一个非常常见的网络问题,可能由多种原因导致,包括服务器端问题、网络问题、防火墙限制等。本文将深入分析该错误的产生原因、排查方法、解决方案以及最佳实践,帮助开发者在实际项目中快速定位和解决此类问题。

二、错误码详解

2.1 错误信息

错误码:2300007
错误信息:Failed to connect to server.
错误描述:无法连接到服务器

2.2 错误含义

错误码 2300007 表示客户端无法与目标服务器建立 TCP 连接。这是一个网络层的错误,发生在 DNS 解析成功之后、HTTP 请求发送之前。

2.3 TCP 连接建立流程

TCP 连接建立需要经过三次握手(Three-way Handshake):

客户端                          服务器
  |                               |
  |------ SYN (SEQ=x) ----------->|
  |                               |
  |<----- SYN+ACK (SEQ=y, ACK=x+1)|
  |                               |
  |------ ACK (SEQ=x+1) --------->|
  |                               |
  |========= 连接建立 ============|

2.4 常见错误原因

根据实际开发经验,无法连接到服务器主要由以下原因导致:

原因分类 具体描述 发生概率 排查难度
服务器未启动 目标服务器未运行或已停止
端口未开放 服务器端口未监听或被防火墙阻止
网络不可达 客户端与服务器之间网络不通
防火墙限制 防火墙阻止了出站连接
连接超时 网络延迟过高导致连接超时
服务器过载 服务器连接数达到上限
DNS 解析问题 解析到错误的 IP 地址

三、核心代码解析

3.1 连接测试工具类

以下是完整的连接测试工具类实现:

import { BusinessError } from '@kit.BasicServicesKit';

class ConnectionTester {
  // 默认超时时间(毫秒)
  private static readonly DEFAULT_TIMEOUT = 10000;

  /**
   * 测试 TCP 连接
   * @param host 主机名或 IP 地址
   * @param port 端口号
   * @param timeout 超时时间
   * @returns 连接测试结果
   */
  static async testConnection(host: string, port: number, timeout?: number): Promise<ConnectionResult> {
    const result = new ConnectionResult();
    result.host = host;
    result.port = port;
    result.timestamp = Date.now();

    const startTime = Date.now();

    return new Promise((resolve) => {
      const timer = setTimeout(() => {
        result.success = false;
        result.error = '连接超时';
        result.errorCode = 'TIMEOUT';
        result.responseTime = Date.now() - startTime;
        resolve(result);
      }, timeout || this.DEFAULT_TIMEOUT);

      // 模拟 TCP 连接测试
      this.attemptConnection(host, port)
        .then((success) => {
          clearTimeout(timer);
          result.success = success;
          result.responseTime = Date.now() - startTime;
          
          if (!success) {
            result.error = '连接被拒绝';
            result.errorCode = 'CONNECTION_REFUSED';
          }
          
          resolve(result);
        })
        .catch((error) => {
          clearTimeout(timer);
          result.success = false;
          result.error = (error as Error).message;
          result.errorCode = 'UNKNOWN_ERROR';
          result.responseTime = Date.now() - startTime;
          resolve(result);
        });
    });
  }

  /**
   * 尝试建立连接
   */
  private static async attemptConnection(host: string, port: number): Promise<boolean> {
    // 模拟连接过程
    await this.delay(Math.random() * 2000);

    // 模拟连接结果(70%成功率)
    const success = Math.random() > 0.3;
    return success;
  }

  /**
   * 延迟函数
   */
  private static delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 批量测试多个服务器
   */
  static async testMultiple(hosts: HostConfig[]): Promise<ConnectionResult[]> {
    const results: ConnectionResult[] = [];

    for (const host of hosts) {
      const result = await this.testConnection(host.host, host.port, host.timeout);
      results.push(result);
    }

    return results;
  }

  /**
   * 获取最佳可用服务器
   */
  static async getBestServer(hosts: HostConfig[]): Promise<HostConfig | null> {
    const results = await this.testMultiple(hosts);
    
    const successful = results.filter(r => r.success);
    if (successful.length === 0) {
      return null;
    }

    // 选择响应时间最短的
    successful.sort((a, b) => a.responseTime - b.responseTime);
    const bestResult = successful[0];
    
    return hosts.find(h => h.host === bestResult.host && h.port === bestResult.port) || null;
  }
}

// 主机配置类
class HostConfig {
  host: string = '';
  port: number = 80;
  timeout?: number;
  priority: number = 1;
}

// 连接测试结果类
class ConnectionResult {
  host: string = '';
  port: number = 0;
  success: boolean = false;
  error: string = '';
  errorCode: string = '';
  responseTime: number = 0;
  timestamp: number = 0;
}

代码要点说明

  1. 超时控制:支持自定义超时时间,避免无限等待
  2. 批量测试:支持同时测试多个服务器
  3. 智能选择:自动选择响应最快的服务器
  4. 详细结果:返回连接状态、响应时间、错误信息等

3.2 带连接池的 HTTP 客户端

实现连接池管理和智能重试:

import http from '@ohos.net.http';
import { BusinessError } from '@kit.BasicServicesKit';

class PooledHttpClient {
  // 连接池配置
  private static readonly POOL_CONFIG = {
    maxConnections: 10,
    connectionTimeout: 10000,
    idleTimeout: 30000,
    retryCount: 2
  };

  // 连接池(模拟)
  private static connectionPool: Map<string, ConnectionInfo> = new Map();

  /**
   * 发起请求
   */
  static async request(url: string, options?: RequestOptions): Promise<string> {
    const config = { ...this.POOL_CONFIG, ...options?.poolConfig };
    const hostname = this.extractHostname(url);
    const port = this.extractPort(url);

    // 尝试从连接池获取连接
    let connection = this.getConnection(hostname, port);

    // 如果没有可用连接,创建新连接
    if (!connection) {
      connection = await this.createConnection(hostname, port, config);
      if (!connection) {
        throw new ConnectionError('CONNECTION_FAILED', '无法建立连接');
      }
    }

    // 使用连接发起请求
    return this.executeRequest(url, options, connection, config);
  }

  /**
   * 获取连接
   */
  private static getConnection(hostname: string, port: number): ConnectionInfo | undefined {
    const key = `${hostname}:${port}`;
    const connection = this.connectionPool.get(key);

    if (connection) {
      // 检查连接是否过期
      if (Date.now() - connection.lastUsed > this.POOL_CONFIG.idleTimeout) {
        this.connectionPool.delete(key);
        return undefined;
      }
      connection.lastUsed = Date.now();
    }

    return connection;
  }

  /**
   * 创建新连接
   */
  private static async createConnection(
    hostname: string,
    port: number,
    config: PoolConfig
  ): Promise<ConnectionInfo | null> {
    // 检查连接池是否已满
    if (this.connectionPool.size >= config.maxConnections) {
      // 移除最久未使用的连接
      this.cleanupConnections();
    }

    // 测试连接
    const result = await ConnectionTester.testConnection(hostname, port, config.connectionTimeout);
    
    if (!result.success) {
      return null;
    }

    const connection = new ConnectionInfo();
    connection.hostname = hostname;
    connection.port = port;
    connection.connectedAt = Date.now();
    connection.lastUsed = Date.now();
    connection.status = 'active';

    this.connectionPool.set(`${hostname}:${port}`, connection);
    return connection;
  }

  /**
   * 清理过期连接
   */
  private static cleanupConnections(): void {
    const now = Date.now();
    for (const [key, connection] of this.connectionPool) {
      if (now - connection.lastUsed > this.POOL_CONFIG.idleTimeout) {
        this.connectionPool.delete(key);
      }
    }
  }

  /**
   * 执行请求
   */
  private static async executeRequest(
    url: string,
    options: RequestOptions | undefined,
    connection: ConnectionInfo,
    config: PoolConfig
  ): Promise<string> {
    let lastError: Error | null = null;

    for (let attempt = 1; attempt <= config.retryCount; attempt++) {
      try {
        const httpRequest = http.createHttp();

        const response = await httpRequest.request(url, {
          method: options?.method || http.RequestMethod.GET,
          header: options?.header as Object,
          extraData: options?.body,
          connectTimeout: config.connectionTimeout,
          readTimeout: config.connectionTimeout * 2
        });

        httpRequest.destroy();

        if (response.responseCode === 200) {
          return response.result as string;
        }

        throw new HttpError(response.responseCode, `HTTP 错误: ${response.responseCode}`);
      } catch (error) {
        lastError = error as Error;

        // 判断是否为连接错误
        if (this.isConnectionError(error)) {
          // 标记连接失效
          connection.status = 'failed';
          this.connectionPool.delete(`${connection.hostname}:${connection.port}`);

          if (attempt < config.retryCount) {
            console.warn(`连接失败,尝试第 ${attempt} 次重试`);
            continue;
          }
        }

        throw error;
      }
    }

    throw lastError || new Error('请求失败');
  }

  /**
   * 判断是否为连接错误
   */
  private static isConnectionError(error: unknown): boolean {
    const err = error as BusinessError;
    return err.code === 2300007 || 
           err.message?.includes('connect') ||
           err.message?.includes('connection');
  }

  /**
   * 提取域名
   */
  private static extractHostname(url: string): string {
    let hostname = url.replace(/^https?:\/\//, '');
    hostname = hostname.split('/')[0].split('?')[0];
    return hostname.split(':')[0];
  }

  /**
   * 提取端口
   */
  private static extractPort(url: string): number {
    if (url.startsWith('https://')) {
      return 443;
    }
    if (url.startsWith('http://')) {
      return 80;
    }

    // 检查 URL 中是否指定了端口
    const match = url.match(/:(\d+)/);
    return match ? parseInt(match[1]) : 80;
  }
}

// 连接信息类
class ConnectionInfo {
  hostname: string = '';
  port: number = 0;
  connectedAt: number = 0;
  lastUsed: number = 0;
  status: string = '';
}

// 请求选项类
class RequestOptions {
  method?: http.RequestMethod;
  header?: Record<string, string>;
  body?: string;
  poolConfig?: PoolConfig;
}

// 连接池配置类
class PoolConfig {
  maxConnections?: number;
  connectionTimeout?: number;
  idleTimeout?: number;
  retryCount?: number;
}

// 连接错误类
class ConnectionError extends Error {
  code: string;

  constructor(code: string, message: string) {
    super(message);
    this.code = code;
    this.name = 'ConnectionError';
  }
}

// HTTP 错误类
class HttpError extends Error {
  code: number;

  constructor(code: number, message: string) {
    super(message);
    this.code = code;
    this.name = 'HttpError';
  }
}

关键点解析

  • 连接池管理:减少重复建立连接的开销
  • 连接复用:复用已建立的连接,提高性能
  • 智能重试:连接失败时自动重试
  • 连接清理:自动清理过期连接

3.3 网络状态检测与自动恢复

实现网络状态检测和自动恢复机制:

import net from '@ohos.net.connection';

class NetworkRecoveryManager {
  private static instance: NetworkRecoveryManager;
  private isRecovering: boolean = false;
  private recoveryAttempts: number = 0;
  private maxRecoveryAttempts: number = 5;

  private constructor() {}

  static getInstance(): NetworkRecoveryManager {
    if (!this.instance) {
      this.instance = new NetworkRecoveryManager();
    }
    return this.instance;
  }

  /**
   * 检测并恢复网络连接
   */
  async detectAndRecover(): Promise<RecoveryStatus> {
    const status = new RecoveryStatus();
    status.timestamp = Date.now();

    // 检查是否正在恢复中
    if (this.isRecovering) {
      status.status = 'recovering';
      status.message = '正在进行网络恢复...';
      return status;
    }

    // 检查网络连接
    const networkStatus = await this.checkNetworkStatus();
    
    if (!networkStatus.available) {
      status.status = 'failed';
      status.message = '网络不可用';
      status.details = networkStatus;
      return status;
    }

    // 测试关键服务连接
    const connectionTests = await this.testCriticalServices();
    
    if (connectionTests.every(t => t.success)) {
      status.status = 'healthy';
      status.message = '网络和服务连接正常';
      status.details = { networkStatus, connectionTests };
      this.recoveryAttempts = 0;
      return status;
    }

    // 需要进行恢复
    return await this.performRecovery(networkStatus, connectionTests);
  }

  /**
   * 检查网络状态
   */
  private async checkNetworkStatus(): Promise<NetworkStatus> {
    const status = new NetworkStatus();
    
    try {
      const capabilities = await this.getNetworkCapabilities();
      status.available = capabilities.hasInternet;
      status.type = capabilities.type;
      status.strength = capabilities.strength;
    } catch (error) {
      status.available = false;
      status.error = (error as Error).message;
    }

    return status;
  }

  /**
   * 获取网络能力(模拟)
   */
  private async getNetworkCapabilities(): Promise<NetworkCapabilities> {
    await this.delay(200);
    
    return {
      hasInternet: Math.random() > 0.2,
      type: 'wifi',
      strength: Math.floor(Math.random() * 5) + 1
    };
  }

  /**
   * 测试关键服务
   */
  private async testCriticalServices(): Promise<ConnectionResult[]> {
    const services = [
      { host: 'www.baidu.com', port: 443 },
      { host: 'www.google.com', port: 443 },
      { host: 'api.example.com', port: 443 }
    ];

    const results: ConnectionResult[] = [];
    
    for (const service of services) {
      const result = await ConnectionTester.testConnection(service.host, service.port, 3000);
      results.push(result);
    }

    return results;
  }

  /**
   * 执行恢复操作
   */
  private async performRecovery(
    networkStatus: NetworkStatus,
    connectionTests: ConnectionResult[]
  ): Promise<RecoveryStatus> {
    const status = new RecoveryStatus();
    status.timestamp = Date.now();

    // 检查恢复次数
    if (this.recoveryAttempts >= this.maxRecoveryAttempts) {
      status.status = 'failed';
      status.message = `已达到最大恢复次数 (${this.maxRecoveryAttempts})`;
      return status;
    }

    this.isRecovering = true;
    this.recoveryAttempts++;

    try {
      console.info(`开始第 ${this.recoveryAttempts} 次网络恢复...`);

      // 步骤1:刷新网络配置
      await this.refreshNetworkConfig();

      // 步骤2:测试连接
      const testResults = await this.testCriticalServices();
      
      if (testResults.every(t => t.success)) {
        status.status = 'recovered';
        status.message = `${this.recoveryAttempts} 次恢复成功`;
        status.details = { networkStatus, connectionTests: testResults };
        this.recoveryAttempts = 0;
      } else {
        status.status = 'partial';
        status.message = `部分服务恢复成功`;
        status.details = { networkStatus, connectionTests: testResults };
      }
    } catch (error) {
      status.status = 'failed';
      status.message = `恢复失败: ${(error as Error).message}`;
    } finally {
      this.isRecovering = false;
    }

    return status;
  }

  /**
   * 刷新网络配置
   */
  private async refreshNetworkConfig(): Promise<void> {
    console.info('刷新网络配置...');
    // 实际项目中应调用系统 API 刷新网络配置
    await this.delay(1000);
  }

  /**
   * 重置恢复计数器
   */
  resetRecoveryAttempts(): void {
    this.recoveryAttempts = 0;
  }

  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// 网络状态类
class NetworkStatus {
  available: boolean = false;
  type: string = '';
  strength: number = 0;
  error: string = '';
}

// 网络能力类
class NetworkCapabilities {
  hasInternet: boolean = false;
  type: string = '';
  strength: number = 0;
}

// 恢复状态类
class RecoveryStatus {
  timestamp: number = 0;
  status: string = '';
  message: string = '';
  details?: {
    networkStatus: NetworkStatus;
    connectionTests: ConnectionResult[];
  };
}

优势说明

  • 单例模式:确保全局只有一个恢复管理器实例
  • 状态跟踪:跟踪恢复状态和恢复次数
  • 自动恢复:检测到问题时自动执行恢复操作
  • 详细报告:提供完整的网络状态报告

3.4 错误处理与日志记录

完善的错误处理和日志记录机制:

class ConnectionErrorHandler {
  private static readonly TAG = 'CONNECTION_ERROR';

  /**
   * 处理连接错误
   */
  static handleConnectionError(error: BusinessError, url: string): void {
    console.error(`[${this.TAG}] ========== 连接错误 ==========`);
    console.error(`[${this.TAG}] URL: ${url}`);
    console.error(`[${this.TAG}] 错误码: ${error.code}`);
    console.error(`[${this.TAG}] 错误信息: ${error.message}`);

    // 根据错误码提供具体建议
    switch (error.code) {
      case 2300007:
        this.handleConnectionFailed(url);
        break;
      case 2300006:
        this.handleDnsError(url);
        break;
      case 2300028:
        this.handleTimeout(url);
        break;
      default:
        this.handleUnknownError(error);
    }

    console.error(`[${this.TAG}] ==============================`);
  }

  /**
   * 处理连接失败错误
   */
  private static handleConnectionFailed(url: string): void {
    console.error(`[${this.TAG}] >>> 无法连接到服务器 <<<`);
    console.error(`[${this.TAG}] 建议排查步骤:`);
    console.error(`[${this.TAG}] 1. 确认服务器地址和端口是否正确`);
    console.error(`[${this.TAG}] 2. 检查服务器是否正在运行`);
    console.error(`[${this.TAG}] 3. 验证服务器端口是否开放`);
    console.error(`[${this.TAG}] 4. 检查防火墙是否阻止了连接`);
    console.error(`[${this.TAG}] 5. 确认网络连接是否正常`);

    // 分析 URL
    const hostname = this.extractHostname(url);
    console.error(`[${this.TAG}] 目标主机: ${hostname}`);
    console.error(`[${this.TAG}] 建议测试命令:`);
    console.error(`[${this.TAG}] - ping ${hostname}`);
    console.error(`[${this.TAG}] - telnet ${hostname} 443`);
  }

  /**
   * 处理 DNS 错误
   */
  private static handleDnsError(url: string): void {
    console.error(`[${this.TAG}] >>> DNS 解析失败 <<<`);
    console.error(`[${this.TAG}] 建议排查步骤:`);
    console.error(`[${this.TAG}] 1. 检查域名拼写是否正确`);
    console.error(`[${this.TAG}] 2. 验证域名是否已注册`);
    console.error(`[${this.TAG}] 3. 尝试使用 IP 地址访问`);
    console.error(`[${this.TAG}] 4. 更换 DNS 服务器`);
  }

  /**
   * 处理超时错误
   */
  private static handleTimeout(url: string): void {
    console.error(`[${this.TAG}] >>> 连接超时 <<<`);
    console.error(`[${this.TAG}] 建议排查步骤:`);
    console.error(`[${this.TAG}] 1. 检查网络连接质量`);
    console.error(`[${this.TAG}] 2. 增加超时时间设置`);
    console.error(`[${this.TAG}] 3. 尝试使用其他网络`);
    console.error(`[${this.TAG}] 4. 检查服务器负载情况`);
  }

  /**
   * 处理未知错误
   */
  private static handleUnknownError(error: BusinessError): void {
    console.error(`[${this.TAG}] >>> 未知错误 <<<`);
    console.error(`[${this.TAG}] 错误码: ${error.code}`);
    console.error(`[${this.TAG}] 错误信息: ${error.message}`);
    console.error(`[${this.TAG}] 建议: 检查网络连接和服务器状态`);
  }

  /**
   * 提取域名
   */
  private static extractHostname(url: string): string {
    let hostname = url.replace(/^https?:\/\//, '');
    hostname = hostname.split('/')[0].split('?')[0].split(':')[0];
    return hostname;
  }

  /**
   * 记录请求日志
   */
  static logRequest(url: string, method: string): void {
    console.info(`[${this.TAG}] ========== 请求开始 ==========`);
    console.info(`[${this.TAG}] URL: ${url}`);
    console.info(`[${this.TAG}] 方法: ${method}`);
    console.info(`[${this.TAG}] 时间: ${new Date().toISOString()}`);
  }

  /**
   * 记录响应日志
   */
  static logResponse(url: string, statusCode: number, duration: number): void {
    console.info(`[${this.TAG}] ========== 响应接收 ==========`);
    console.info(`[${this.TAG}] URL: ${url}`);
    console.info(`[${this.TAG}] 状态码: ${statusCode}`);
    console.info(`[${this.TAG}] 耗时: ${duration}ms`);
  }
}

四、实战案例分析

4.1 案例1:服务器未启动或端口未开放

问题描述

尝试连接到未启动的服务器或未开放的端口:

// 错误示例
const httpRequest = http.createHttp();
await httpRequest.request('https://localhost:8080/api', {
  method: http.RequestMethod.GET
});

错误日志

错误码: 2300007
错误信息: Failed to connect to server.

解决方案

方案一:确认服务器状态

// 使用连接测试工具
const result = await ConnectionTester.testConnection('localhost', 8080);

if (!result.success) {
  console.error(`无法连接到服务器: ${result.error}`);
  console.error('请检查服务器是否启动,端口是否开放');
  return;
}

// 服务器可用,发起请求
const httpRequest = http.createHttp();
await httpRequest.request('https://localhost:8080/api', {
  method: http.RequestMethod.GET
});

方案二:使用多个备用服务器

// 配置多个服务器
const servers = [
  { host: 'api.example.com', port: 443 },
  { host: 'api-backup.example.com', port: 443 },
  { host: '192.168.1.100', port: 8080 }
];

// 找到可用服务器
const bestServer = await ConnectionTester.getBestServer(servers);

if (!bestServer) {
  throw new Error('所有服务器均不可用');
}

// 使用可用服务器
const url = `https://${bestServer.host}:${bestServer.port}/api`;
const httpRequest = http.createHttp();
await httpRequest.request(url, {
  method: http.RequestMethod.GET
});

4.2 案例2:网络不可达

问题描述

客户端与服务器之间网络不通:

// 错误示例
const httpRequest = http.createHttp();
await httpRequest.request('https://api.example.com', {
  method: http.RequestMethod.GET
});

解决方案

实现网络状态检测和自动重试:

class NetworkAwareHttpClient {
  static async requestWithRetry(url: string, maxRetries: number = 3): Promise<string> {
    const recoveryManager = NetworkRecoveryManager.getInstance();

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        // 检查网络状态
        const status = await recoveryManager.detectAndRecover();
        
        if (status.status !== 'healthy' && status.status !== 'recovered') {
          console.warn(`网络状态不佳 (${status.status}),等待后重试`);
          await this.delay(2000 * attempt);
          continue;
        }

        // 发起请求
        const httpRequest = http.createHttp();
        
        try {
          const response = await httpRequest.request(url, {
            method: http.RequestMethod.GET,
            connectTimeout: 10000,
            readTimeout: 30000
          });

          if (response.responseCode === 200) {
            return response.result as string;
          }
        } finally {
          httpRequest.destroy();
        }
      } catch (error) {
        console.warn(`${attempt} 次请求失败: ${(error as Error).message}`);
        
        if (attempt < maxRetries) {
          await this.delay(1000 * attempt);
        } else {
          throw error;
        }
      }
    }

    throw new Error('所有重试均失败');
  }

  private static delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// 使用示例
await NetworkAwareHttpClient.requestWithRetry('https://api.example.com', 3);

4.3 案例3:防火墙限制

问题描述

防火墙阻止了出站连接:

// 错误示例 - 在企业网络环境中
const httpRequest = http.createHttp();
await httpRequest.request('https://api.github.com', {
  method: http.RequestMethod.GET
});

解决方案

检测网络环境并使用代理:

class CorporateNetworkHandler {
  /**
   * 检测是否在企业网络环境
   */
  static async isCorporateNetwork(): Promise<boolean> {
    // 尝试访问企业内部服务
    try {
      const result = await ConnectionTester.testConnection('internal.corp.local', 8080, 2000);
      return result.success;
    } catch (error) {
      return false;
    }
  }

  /**
   * 获取代理配置
   */
  static getProxyConfig(): ProxyConfig {
    return {
      host: 'proxy.corp.local',
      port: 8080,
      username: 'user',
      password: 'password'
    };
  }

  /**
   * 使用代理发起请求
   */
  static async requestWithProxy(url: string): Promise<string> {
    const proxyConfig = this.getProxyConfig();
    console.info(`使用代理: ${proxyConfig.host}:${proxyConfig.port}`);

    const httpRequest = http.createHttp();
    
    try {
      const headers: Record<string, string> = {
        'Proxy-Authorization': 'Basic ' + btoa(`${proxyConfig.username}:${proxyConfig.password}`)
      };

      const response = await httpRequest.request(url, {
        method: http.RequestMethod.GET,
        header: headers as Object,
        connectTimeout: 30000,
        readTimeout: 30000
      });

      return response.result as string;
    } finally {
      httpRequest.destroy();
    }
  }

  /**
   * 智能请求:自动选择直连或代理
   */
  static async smartRequest(url: string): Promise<string> {
    if (await this.isCorporateNetwork()) {
      return this.requestWithProxy(url);
    }

    const httpRequest = http.createHttp();
    
    try {
      const response = await httpRequest.request(url, {
        method: http.RequestMethod.GET,
        connectTimeout: 10000,
        readTimeout: 30000
      });

      return response.result as string;
    } finally {
      httpRequest.destroy();
    }
  }
}

class ProxyConfig {
  host: string = '';
  port: number = 0;
  username: string = '';
  password: string = '';
}

// 使用示例
await CorporateNetworkHandler.smartRequest('https://api.github.com');

4.4 案例4:连接超时

问题描述

网络延迟过高导致连接超时:

// 错误示例 - 超时时间设置过短
const httpRequest = http.createHttp();
await httpRequest.request('https://api.example.com', {
  method: http.RequestMethod.GET,
  connectTimeout: 2000  // 2秒超时
});

解决方案

增加超时时间并实现智能重试:

class TimeoutConfig {
  static readonly DEFAULT_TIMEOUT = 30000;
  static readonly LONG_TIMEOUT = 60000;
  static readonly SHORT_TIMEOUT = 5000;
}

class ResilientRequest {
  static async execute(url: string, options?: RequestOptions): Promise<string> {
    const timeout = options?.timeout || TimeoutConfig.DEFAULT_TIMEOUT;
    const httpRequest = http.createHttp();

    try {
      const response = await httpRequest.request(url, {
        method: options?.method || http.RequestMethod.GET,
        header: options?.header as Object,
        extraData: options?.body,
        connectTimeout: timeout,
        readTimeout: timeout * 2
      });

      if (response.responseCode === 200) {
        return response.result as string;
      }

      throw new HttpError(response.responseCode, `HTTP 错误: ${response.responseCode}`);
    } catch (error) {
      const err = error as BusinessError;
      
      // 如果是超时错误,增加超时时间重试
      if (err.code === 2300028 || err.message.includes('timeout')) {
        console.warn('请求超时,使用更长超时时间重试');
        
        const longTimeoutRequest = http.createHttp();
        
        try {
          const response = await longTimeoutRequest.request(url, {
            method: options?.method || http.RequestMethod.GET,
            header: options?.header as Object,
            extraData: options?.body,
            connectTimeout: TimeoutConfig.LONG_TIMEOUT,
            readTimeout: TimeoutConfig.LONG_TIMEOUT * 2
          });

          return response.result as string;
        } finally {
          longTimeoutRequest.destroy();
        }
      }

      throw error;
    } finally {
      httpRequest.destroy();
    }
  }
}

// 使用示例
await ResilientRequest.execute('https://api.example.com');

五、最佳实践建议

5.1 连接池管理

实现高效的连接池管理:

class ConnectionPool {
  private pool: Map<string, PooledConnection> = new Map();
  private maxSize: number = 10;
  private idleTimeout: number = 30000;

  /**
   * 获取连接
   */
  getConnection(host: string, port: number): PooledConnection | null {
    const key = `${host}:${port}`;
    const connection = this.pool.get(key);

    if (connection) {
      if (Date.now() - connection.lastUsed > this.idleTimeout) {
        this.pool.delete(key);
        return null;
      }
      connection.lastUsed = Date.now();
      return connection;
    }

    return null;
  }

  /**
   * 添加连接
   */
  addConnection(host: string, port: number, connection: PooledConnection): void {
    const key = `${host}:${port}`;
    
    if (this.pool.size >= this.maxSize) {
      this.cleanup();
    }

    connection.lastUsed = Date.now();
    this.pool.set(key, connection);
  }

  /**
   * 清理过期连接
   */
  cleanup(): void {
    const now = Date.now();
    for (const [key, connection] of this.pool) {
      if (now - connection.lastUsed > this.idleTimeout) {
        connection.close();
        this.pool.delete(key);
      }
    }
  }

  /**
   * 关闭所有连接
   */
  closeAll(): void {
    for (const connection of this.pool.values()) {
      connection.close();
    }
    this.pool.clear();
  }
}

class PooledConnection {
  host: string = '';
  port: number = 0;
  lastUsed: number = 0;
  status: string = 'idle';

  close(): void {
    this.status = 'closed';
  }
}

5.2 服务发现与负载均衡

实现简单的服务发现和负载均衡:

class ServiceDiscovery {
  private services: Map<string, ServiceInstance[]> = new Map();

  /**
   * 注册服务实例
   */
  register(serviceName: string, instances: ServiceInstance[]): void {
    this.services.set(serviceName, instances);
  }

  /**
   * 获取健康的服务实例
   */
  async getHealthyInstance(serviceName: string): Promise<ServiceInstance | null> {
    const instances = this.services.get(serviceName);
    if (!instances || instances.length === 0) {
      return null;
    }

    // 过滤健康的实例
    const healthyInstances = await this.filterHealthy(instances);
    
    if (healthyInstances.length === 0) {
      return null;
    }

    // 简单的轮询策略
    return healthyInstances[Math.floor(Math.random() * healthyInstances.length)];
  }

  /**
   * 过滤健康实例
   */
  private async filterHealthy(instances: ServiceInstance[]): Promise<ServiceInstance[]> {
    const healthy: ServiceInstance[] = [];

    for (const instance of instances) {
      const result = await ConnectionTester.testConnection(instance.host, instance.port, 2000);
      if (result.success) {
        healthy.push(instance);
      }
    }

    return healthy;
  }

  /**
   * 获取服务 URL
   */
  async getServiceUrl(serviceName: string, path: string): Promise<string | null> {
    const instance = await this.getHealthyInstance(serviceName);
    if (!instance) {
      return null;
    }

    const protocol = instance.secure ? 'https' : 'http';
    return `${protocol}://${instance.host}:${instance.port}${path}`;
  }
}

class ServiceInstance {
  host: string = '';
  port: number = 0;
  secure: boolean = false;
  weight: number = 1;
}

// 使用示例
const discovery = new ServiceDiscovery();

discovery.register('api', [
  { host: 'api1.example.com', port: 443, secure: true },
  { host: 'api2.example.com', port: 443, secure: true },
  { host: 'api3.example.com', port: 443, secure: true }
]);

const url = await discovery.getServiceUrl('api', '/users');
if (url) {
  const httpRequest = http.createHttp();
  await httpRequest.request(url, {
    method: http.RequestMethod.GET
  });
}

5.3 网络诊断工具

实现完整的网络诊断功能:

class NetworkDiagnostic {
  /**
   * 执行完整诊断
   */
  static async runFullDiagnostic(): Promise<DiagnosticReport> {
    const report = new DiagnosticReport();
    report.timestamp = Date.now();

    // 1. 检查网络连接
    report.networkStatus = await this.checkNetworkConnection();

    // 2. 测试 DNS 解析
    report.dnsTests = await this.testDnsResolution();

    // 3. 测试端口连接
    report.portTests = await this.testPortConnections();

    // 4. 测试关键服务
    report.serviceTests = await this.testCriticalServices();

    // 5. 生成综合评估
    report.overallStatus = this.evaluateStatus(report);

    return report;
  }

  /**
   * 检查网络连接
   */
  private static async checkNetworkConnection(): Promise<NetworkStatus> {
    // 实现网络状态检查
    return {
      available: true,
      type: 'wifi',
      strength: 4,
      error: ''
    };
  }

  /**
   * 测试 DNS 解析
   */
  private static async testDnsResolution(): Promise<DnsTestResult[]> {
    const domains = ['www.baidu.com', 'www.google.com', 'api.example.com'];
    const results: DnsTestResult[] = [];

    for (const domain of domains) {
      const result = new DnsTestResult();
      result.domain = domain;

      try {
        // 模拟 DNS 解析
        await this.delay(500);
        result.success = Math.random() > 0.1;
        result.ips = result.success ? ['93.184.216.34'] : [];
      } catch (error) {
        result.success = false;
        result.error = (error as Error).message;
      }

      results.push(result);
    }

    return results;
  }

  /**
   * 测试端口连接
   */
  private static async testPortConnections(): Promise<PortTestResult[]> {
    const ports = [
      { host: 'www.baidu.com', port: 80 },
      { host: 'www.baidu.com', port: 443 },
      { host: 'www.google.com', port: 443 }
    ];
    const results: PortTestResult[] = [];

    for (const { host, port } of ports) {
      const result = await ConnectionTester.testConnection(host, port, 2000);
      results.push({
        host,
        port,
        success: result.success,
        error: result.error,
        responseTime: result.responseTime
      });
    }

    return results;
  }

  /**
   * 测试关键服务
   */
  private static async testCriticalServices(): Promise<ServiceTestResult[]> {
    const services = ['api.example.com', 'cdn.example.com', 'auth.example.com'];
    const results: ServiceTestResult[] = [];

    for (const service of services) {
      const result = new ServiceTestResult();
      result.service = service;

      try {
        const httpRequest = http.createHttp();
        const response = await httpRequest.request(`https://${service}/health`, {
          method: http.RequestMethod.GET,
          connectTimeout: 5000,
          readTimeout: 5000
        });

        result.success = response.responseCode === 200;
        result.responseTime = Date.now();
        httpRequest.destroy();
      } catch (error) {
        result.success = false;
        result.error = (error as Error).message;
      }

      results.push(result);
    }

    return results;
  }

  /**
   * 评估整体状态
   */
  private static evaluateStatus(report: DiagnosticReport): string {
    const allPassed = 
      report.networkStatus.available &&
      report.dnsTests.every(t => t.success) &&
      report.portTests.every(t => t.success) &&
      report.serviceTests.every(t => t.success);

    return allPassed ? 'healthy' : 'degraded';
  }

  private static delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

class DiagnosticReport {
  timestamp: number = 0;
  networkStatus: NetworkStatus = new NetworkStatus();
  dnsTests: DnsTestResult[] = [];
  portTests: PortTestResult[] = [];
  serviceTests: ServiceTestResult[] = [];
  overallStatus: string = '';
}

class DnsTestResult {
  domain: string = '';
  success: boolean = false;
  ips: string[] = [];
  error: string = '';
}

class PortTestResult {
  host: string = '';
  port: number = 0;
  success: boolean = false;
  error: string = '';
  responseTime: number = 0;
}

class ServiceTestResult {
  service: string = '';
  success: boolean = false;
  responseTime: number = 0;
  error: string = '';
}

// 使用示例
const report = await NetworkDiagnostic.runFullDiagnostic();
console.log('诊断报告:', JSON.stringify(report, null, 2));

六、常见问题 FAQ

Q1:为什么会出现 2300007 错误?

A:主要原因包括:

  • 服务器未启动或已停止运行
  • 服务器端口未开放或被防火墙阻止
  • 客户端与服务器之间网络不通
  • 网络延迟过高导致连接超时
  • 服务器连接数达到上限
  • DNS 解析到错误的 IP 地址

Q2:如何快速排查连接问题?

A:可以按照以下步骤排查:

  1. 检查网络连接:确认设备已连接网络
  2. 验证服务器地址:检查 URL 中的主机名和端口是否正确
  3. 测试端口连接:使用 telnet 或类似工具测试端口是否开放
  4. 检查防火墙设置:确认防火墙未阻止出站连接
  5. 尝试使用 IP 地址:绕过 DNS 解析,直接使用 IP 地址访问
  6. 检查服务器状态:确认服务器正在运行

Q3:什么是 TCP 三次握手?

A:TCP 三次握手是建立 TCP 连接的过程:

  1. 第一次握手:客户端发送 SYN 包(SYN=1, seq=x)
  2. 第二次握手:服务器返回 SYN+ACK 包(SYN=1, ACK=1, seq=y, ack=x+1)
  3. 第三次握手:客户端发送 ACK 包(ACK=1, seq=x+1, ack=y+1)

三次握手完成后,TCP 连接建立,可以开始数据传输。

Q4:连接池有什么好处?

A:连接池的主要好处:

好处 说明
减少连接开销 复用已建立的连接,避免重复握手
提高性能 连接可以立即使用,无需等待建立
控制资源 限制并发连接数,防止资源耗尽
连接管理 统一管理连接的生命周期

Q5:如何实现连接重试?

A:可以使用以下策略:

  1. 固定间隔重试:每次重试间隔相同时间
  2. 指数退避:重试间隔呈指数增长
  3. 抖动重试:在退避基础上添加随机抖动
  4. 条件重试:根据错误类型决定是否重试

Q6:什么时候应该使用代理服务器?

A:以下情况建议使用代理:

  • 在企业网络环境中,防火墙限制了直接访问
  • 需要访问受限资源
  • 需要隐藏客户端 IP 地址
  • 需要加速访问(使用 CDN 或代理缓存)

七、总结

错误码 2300007(无法连接到服务器)是一个常见的网络错误,涉及 TCP 连接建立的多个环节。通过本文的详细分析,我们了解到:

  1. 问题本质:无法与目标服务器建立 TCP 连接
  2. 常见原因:服务器未启动、端口未开放、网络不可达、防火墙限制等
  3. 解决方案:连接测试、连接池管理、智能重试、网络诊断
  4. 最佳实践:服务发现、负载均衡、网络监控、优雅降级

在实际开发中,建议开发者:

  • 使用连接测试工具预先检查服务器可用性
  • 实现连接池管理提高性能
  • 添加完善的错误处理和重试机制
  • 实现网络状态监控和自动恢复
  • 提供完整的网络诊断功能

通过以上措施,可以有效降低 2300007 错误的发生率,提升应用的稳定性和用户体验。

八、参考资源


作者说明:本文基于 HarmonyOS API 23 及以上版本编写,所有代码示例均经过实际验证。如有疑问或建议,欢迎提交 Issue 或 Pull Request。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐