HarmonyOS 网络编程实战:HTTP、WebSocket 与 Socket 通信详解## 一、前言网络通信是现代移动应用的基石。HarmonyOS 为开发者提供了完备的网络编程能力,从高层的 HTTP 请求到底层的 Socket 通信,覆盖了各种网络场景。本文将以 HarmonyOS 5.0.0(API 12)为基础,通过完整可运行的代码示例,深入讲解三种核心网络通信方式。## 二、网络权限配置在 module.json5 中配置网络权限:{

“module”: {
“requestPermissions”: [
{ “name”: “ohos.permission.INTERNET” },
{ “name”: “ohos.permission.GET_NETWORK_INFO” }
]
}
}

三、HTTP 请求:@kit.NetworkKit### 3.1 GET 请求import { http } from ‘@kit.NetworkKit’;

@Component
struct HttpGetDemo {
@State response: string = ‘等待请求…’;
@State isLoading: boolean = false;

async fetchData() {
this.isLoading = true;
this.response = ‘请求中…’;
const httpRequest = http.createHttp();

try {
  const result = await httpRequest.request(
    'https://httpbin.org/get?name=HarmonyOS',
    {
      method: http.RequestMethod.GET,
      header: { 'Content-Type': 'application/json' },
      connectTimeout: 10000,
      readTimeout: 15000
    }
  );

  if (result.responseCode === 200) {
    const data = JSON.parse(result.result as string);
    this.response = `请求成功! URL: ${data.url}`;
  } else {
    this.response = `请求失败: ${result.responseCode}`;
  }
} catch (error) {
  this.response = `网络错误: ${JSON.stringify(error)}`;
} finally {
  this.isLoading = false;
  httpRequest.destroy(); // 销毁请求实例
}

}

build() {
Column({ space: 20 }) {
Text(‘HTTP GET 请求示例’).fontSize(24).fontWeight(FontWeight.Bold)

  Button('发送 GET 请求').fontSize(16).enabled(!this.isLoading)
    .onClick(() => { this.fetchData() })

  Text(this.response).fontSize(14).padding(12)
    .backgroundColor('#F5F5F5').borderRadius(8).width('100%')

  if (this.isLoading) {
    LoadingProgress().width(40).height(40).color('#007AFF')
  }
}.width('100%').height('100%').padding(20)

}
}

3.2 POST 请求(JSON)import { http } from ‘@kit.NetworkKit’;

@Component
struct HttpPostDemo {
@State response: string = ‘’;
@State isSubmitting: boolean = false;

async submitData(username: string, password: string) {
this.isSubmitting = true;
const httpRequest = http.createHttp();

try {
  const requestBody = JSON.stringify({
    username, password, client: 'HarmonyOS-App', version: '1.0.0'
  });

  const result = await httpRequest.request('https://httpbin.org/post', {
    method: http.RequestMethod.POST,
    header: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer your-token-here'
    },
    extraData: requestBody,
    connectTimeout: 10000,
    readTimeout: 15000
  });

  if (result.responseCode === 200) {
    const data = JSON.parse(result.result as string);
    this.response = `提交成功! 服务端返回: ${data.json}`;
  } else {
    this.response = `提交失败: ${result.responseCode}`;
  }
} catch (error) {
  this.response = `网络错误: ${error}`;
} finally {
  this.isSubmitting = false;
  httpRequest.destroy();
}

}

build() {
Column({ space: 20 }) {
Text(‘HTTP POST 请求示例’).fontSize(24).fontWeight(FontWeight.Bold)
Button(‘模拟登录提交’).fontSize(16).enabled(!this.isSubmitting)
.onClick(() => { this.submitData(‘testuser’, ‘123456’) })
Text(this.response).fontSize(14).padding(12)
.backgroundColor(‘#F5F5F5’).borderRadius(8).width(‘100%’)
.maxLines(15).textOverflow({ overflow: TextOverflow.Ellipsis })
}.width(‘100%’).height(‘100%’).padding(20)
}
}

3.3 文件上传import { http } from ‘@kit.NetworkKit’;

@Component
struct FileUploadDemo {
@State uploadProgress: number = 0;
@State status: string = ‘等待上传…’;

async uploadFile(filePath: string) {
this.status = ‘上传中…’;
const httpRequest = http.createHttp();

try {
  httpRequest.on('dataReceiveProgress', (receivedSize: number, totalSize: number) => {
    this.uploadProgress = Math.round((receivedSize / totalSize) * 100);
    this.status = `上传中: ${this.uploadProgress}%`;
  });

  const result = await httpRequest.request('https://httpbin.org/post', {
    method: http.RequestMethod.POST,
    header: { 'Content-Type': 'multipart/form-data' },
    extraData: { file: filePath, description: '测试文件上传' },
    connectTimeout: 30000, readTimeout: 60000
  });

  this.status = result.responseCode === 200 ? '上传成功!' : `上传失败: ${result.responseCode}`;
} catch (error) {
  this.status = `错误: ${error}`;
} finally {
  httpRequest.destroy();
}

}

build() {
Column({ space: 20 }) {
Text(‘文件上传示例’).fontSize(24).fontWeight(FontWeight.Bold)
Progress({ value: this.uploadProgress, total: 100 }).width(‘80%’)
Text(this.status).fontSize(16).fontColor(‘#007AFF’)
Button(‘上传文件’).fontSize(16)
.onClick(async () => { await this.uploadFile(‘/data/storage/el2/base/files/demo.txt’) })
}.width(‘100%’).padding(20)
}
}

四、WebSocket:实时双向通信### 4.1 WebSocket 客户端import { webSocket } from ‘@kit.NetworkKit’;

@Entry
@Component
struct WebSocketDemo {
@State messages: string[] = [];
@State connectionStatus: string = ‘未连接’;
@State inputText: string = ‘’;
private ws?: webSocket.WebSocket;

connectWebSocket() {
this.ws = webSocket.createWebSocket();

this.ws.on('open', (err: Object, value: webSocket.OpenResult) => {
  this.connectionStatus = '已连接';
});

this.ws.on('message', (err: Object, value: string | ArrayBuffer) => {
  const message = typeof value === 'string' ? value : '收到二进制数据';
  this.messages.push(`[${new Date().toLocaleTimeString()}] 服务端: ${message}`);
});

this.ws.on('close', (err: Object, value: webSocket.CloseResult) => {
  this.connectionStatus = '已断开';
  console.info(`WebSocket 关闭: code=${value.code}, reason=${value.reason}`);
});

this.ws.on('error', (err: Object) => {
  this.connectionStatus = '连接错误';
  console.error(`WebSocket 错误: ${JSON.stringify(err)}`);
});

this.ws.connect('wss://echo.websocket.org', (err: Object, value: boolean) => {
  if (!err) {
    this.connectionStatus = '已连接';
    this.messages.push('[系统] 连接建立成功');
  }
});

}

sendMessage() {
if (!this.ws || !this.inputText.trim()) return;
this.ws.send(this.inputText.trim(), (err: Object, value: boolean) => {
if (!err) {
this.messages.push([${new Date().toLocaleTimeString()}] 我: ${this.inputText});
this.inputText = ‘’;
}
});
}

disconnect() {
if (this.ws) {
this.ws.close({ code: 1000, reason: ‘用户主动断开’ });
}
}

build() {
Column({ space: 12 }) {
Row() {
Text(‘💬 WebSocket 聊天’).fontSize(24).fontWeight(FontWeight.Bold)
}.width(‘100%’)

  Row({ space: 8 }) {
    Circle().width(8).height(8)
      .fill(this.connectionStatus === '已连接' ? '#4CAF50' : '#FF4444')
    Text(this.connectionStatus).fontSize(14).fontColor('#666')
  }

  Button(this.connectionStatus === '已连接' ? '断开连接' : '连接服务器')
    .fontSize(16)
    .backgroundColor(this.connectionStatus === '已连接' ? '#FF4444' : '#007AFF')
    .width('100%')
    .onClick(() => {
      this.connectionStatus === '已连接' ? this.disconnect() : this.connectWebSocket()
    })

  Divider()

  List({ space: 6 }) {
    ForEach(this.messages, (msg: string) => {
      ListItem() {
        Text(msg).fontSize(13)
          .fontColor(msg.includes('我:') ? '#007AFF' : '#333')
          .width('100%').padding(8)
          .backgroundColor(msg.includes('系统') ? '#FFF8E1' :
            msg.includes('我:') ? '#E3F2FD' : '#F5F5F5')
          .borderRadius(6)
      }
    })
  }.layoutWeight(1).width('100%')

  Row({ space: 8 }) {
    TextInput({ placeholder: '输入消息...', text: this.inputText })
      .layoutWeight(1).height(44)
      .onChange((value: string) => { this.inputText = value })
    Button('发送').fontSize(14)
      .enabled(this.connectionStatus === '已连接' && this.inputText.trim() !== '')
      .onClick(() => { this.sendMessage() })
  }.width('100%')
}.width('100%').height('100%').padding(16)

}
}

4.2 心跳保活function setupHeartbeat(ws: webSocket.WebSocket, intervalMs: number = 30000) {

let heartbeatTimer: number | null = null;

const startHeartbeat = () => {
heartbeatTimer = setInterval(() => {
if (ws) {
ws.send(‘ping’, (err: Object) => {
if (err) console.error(‘心跳发送失败, 尝试重连…’);
});
}
}, intervalMs);
};

ws.on(‘message’, (err: Object, value: string | ArrayBuffer) => {
if (value === ‘pong’) console.info(‘收到 pong’);
});

ws.on(‘open’, () => { startHeartbeat() });

ws.on(‘close’, () => {
if (heartbeatTimer !== null) { clearInterval(heartbeatTimer); heartbeatTimer = null }
});

return { startHeartbeat };
}

五、Socket:底层网络通信### 5.1 TCP Socket 客户端import { socket } from ‘@kit.NetworkKit’;

@Entry
@Component
struct TcpSocketDemo {
@State log: string[] = [];
@State isConnected: boolean = false;
private tcp?: socket.TCPSocket;

addLog(text: string) {
this.log.push([${new Date().toLocaleTimeString()}] ${text});
}

async connectTcp(host: string, port: number) {
this.tcp = socket.constructTCPSocketInstance();
const bindAddress: socket.NetAddress = { address: ‘0.0.0.0’, port: 0, family: 1 };

try {
  await this.tcp.bind(bindAddress);
  this.addLog('Socket 绑定成功');

  const remoteAddress: socket.NetAddress = { address: host, port, family: 1 };
  await this.tcp.connect(remoteAddress);
  this.isConnected = true;
  this.addLog(`已连接到 ${host}:${port}`);

  this.tcp.on('message', (value: socket.SocketMessage) => {
    const decoder = new util.TextDecoder('utf-8');
    const message = decoder.decodeWithStream(new Uint8Array(value.message), { stream: false });
    this.addLog(`收到: ${message}`);
  });

  this.tcp.on('close', () => { this.isConnected = false; this.addLog('连接已关闭') });
  this.tcp.on('error', (err: Object) => { this.addLog(`错误: ${JSON.stringify(err)}`) });

  await this.tcp.send({ data: 'Hello Server!' });
} catch (error) {
  this.addLog(`连接失败: ${error}`);
}

}

async sendData(data: string) {
if (!this.tcp || !this.isConnected) return;
try {
await this.tcp.send({ data });
this.addLog(发送: ${data});
} catch (error) {
this.addLog(发送失败: ${error});
}
}

async disconnect() {
if (this.tcp) { await this.tcp.close(); this.tcp = undefined; this.isConnected = false }
}

build() {
Column({ space: 12 }) {
Text(‘🔌 TCP Socket 示例’).fontSize(24).fontWeight(FontWeight.Bold)
Text(状态: ${this.isConnected ? '🟢 已连接' : '🔴 未连接'}).fontSize(16)

  Row({ space: 8 }) {
    Button('连接服务器').fontSize(14).enabled(!this.isConnected)
      .onClick(() => { this.connectTcp('127.0.0.1', 8080) })
    Button('断开连接').fontSize(14).backgroundColor('#FF4444').enabled(this.isConnected)
      .onClick(() => { this.disconnect() })
  }

  Divider()

  List({ space: 4 }) {
    ForEach(this.log, (msg: string) => {
      ListItem() {
        Text(msg).fontSize(12).fontFamily('monospace').width('100%')
          .padding(6).backgroundColor('#F5F5F5').borderRadius(4)
      }
    })
  }.layoutWeight(1).width('100%')
}.width('100%').height('100%').padding(16)

}
}

六、网络状态监听import { connection } from ‘@kit.NetworkKit’;

@Entry
@Component
struct NetworkMonitor {
@State networkType: string = ‘检测中…’;
@State isOnline: boolean = true;
private netConnection?: connection.NetConnection;

aboutToAppear() {
this.netConnection = connection.createNetConnection();

this.netConnection.register((error: Object) => {
  if (error) console.error(`网络监听注册失败: ${error}`);
});

this.netConnection.on('netAvailable', () => { this.isOnline = true });
this.netConnection.on('netUnavailable', () => { this.isOnline = false });

this.netConnection.on('netConnectionPropertiesChange',
  (data: connection.NetConnectionProperty) => {
    if (data.networkCap) {
      const caps = data.networkCap;
      if (caps.includes(connection.NetCapability.NET_CAPABILITY_WIFI)) {
        this.networkType = 'WiFi';
      } else if (caps.includes(connection.NetCapability.NET_CAPABILITY_CELLULAR)) {
        this.networkType = '蜂窝网络';
      } else {
        this.networkType = '以太网';
      }
    }
  }
);

this.checkCurrentNetwork();

}

async checkCurrentNetwork() {
try {
const netHandle = await connection.getDefaultNet();
const netCaps = await connection.getNetCapabilities(netHandle);
if (netCaps.networkCap?.includes(connection.NetCapability.NET_CAPABILITY_WIFI)) {
this.networkType = ‘WiFi’;
} else if (netCaps.networkCap?.includes(connection.NetCapability.NET_CAPABILITY_CELLULAR)) {
this.networkType = ‘蜂窝网络’;
}
} catch (error) {
console.error(获取网络状态失败: ${error});
}
}

build() {
Column({ space: 16 }) {
Text(‘📶 网络状态监控’).fontSize(24).fontWeight(FontWeight.Bold)

  Row({ space: 12 }) {
    Text('网络状态:').fontSize(16)
    Circle().width(10).height(10).fill(this.isOnline ? '#4CAF50' : '#FF4444')
    Text(this.isOnline ? '在线' : '离线').fontSize(16)
      .fontColor(this.isOnline ? '#4CAF50' : '#FF4444')
  }

  Row({ space: 12 }) {
    Text('网络类型:').fontSize(16)
    Text(this.networkType).fontSize(16).fontWeight(FontWeight.Medium).fontColor('#007AFF')
  }

  Button('刷新网络状态').fontSize(16)
    .onClick(() => { this.checkCurrentNetwork() })
}.width('100%').padding(20)

}
}

七、完整实战:天气查询应用import { http, connection } from ‘@kit.NetworkKit’;

interface WeatherData {
city: string; temperature: string; weather: string;
humidity: string; wind: string;
}

@Entry
@Component
struct WeatherApp {
@State weather: WeatherData = { city: ‘’, temperature: ‘’, weather: ‘’, humidity: ‘’, wind: ‘’ };
@State isLoading: boolean = false;
@State error: string = ‘’;
@State isOnline: boolean = true;

async fetchWeather(city: string) {
if (!this.isOnline) { this.error = ‘网络未连接’; return }
this.isLoading = true; this.error = ‘’;
const httpRequest = http.createHttp();

try {
  const result = await httpRequest.request(
    `https://wttr.in/${encodeURIComponent(city)}?format=j1`,
    { method: http.RequestMethod.GET, connectTimeout: 10000, readTimeout: 15000 }
  );

  if (result.responseCode === 200) {
    const data = JSON.parse(result.result as string);
    const current = data.current_condition[0];
    this.weather = {
      city,
      temperature: `${current.temp_C}°C`,
      weather: current.weatherDesc[0].value,
      humidity: `${current.humidity}%`,
      wind: `${current.winddir16Point} ${current.windspeedKmph}km/h`
    };
  } else {
    this.error = `请求失败: ${result.responseCode}`;
  }
} catch (error) {
  this.error = `网络错误: ${error}`;
} finally {
  this.isLoading = false;
  httpRequest.destroy();
}

}

build() {
Column({ space: 16 }) {
Text(‘🌤 天气查询’).fontSize(28).fontWeight(FontWeight.Bold)

  if (!this.isOnline) {
    Text('⚠️ 网络未连接').fontSize(14).fontColor('#FF4444')
      .padding(8).backgroundColor('#FFEBEE').borderRadius(8).width('100%')
  }

  Row({ space: 8 }) {
    TextInput({ placeholder: '输入城市名, 如: Beijing' }).layoutWeight(1).height(44)
  }.width('100%')

  Button('查询天气').fontSize(16).enabled(this.isOnline && !this.isLoading).width('100%')
    .onClick(() => { this.fetchWeather('Beijing') })

  if (this.isLoading) { LoadingProgress().width(40).height(40) }
  if (this.error) { Text(this.error).fontSize(14).fontColor('#FF4444') }

  if (this.weather.temperature) {
    Column({ space: 12 }) {
      Text(`📍 ${this.weather.city}`).fontSize(22).fontWeight(FontWeight.Bold)
      Text(this.weather.temperature).fontSize(48).fontWeight(FontWeight.Bold).fontColor('#007AFF')
      Text(this.weather.weather).fontSize(18).fontColor('#666')
      Row({ space: 24 }) {
        Text(`💧 ${this.weather.humidity}`).fontSize(14).fontColor('#888')
        Text(`💨 ${this.weather.wind}`).fontSize(14).fontColor('#888')
      }
    }
    .width('100%').padding(24).backgroundColor('#F0F8FF').borderRadius(16)
    .alignItems(HorizontalAlign.Center)
  }
}.width('100%').height('100%').padding(20)

}
}

八、常见问题与最佳实践| 问题 | 解答 ||------|------|| HTTP 请求超时? | 设置合理 connectTimeout/readTimeout || 取消请求? | 调用 httpRequest.destroy() || WebSocket 断线重连? | close 回调中实现指数退避重连 || 请求拦截? | 封装统一 request 方法,添加 token/日志 || Socket 粘包? | 自定义协议头包含消息长度字段 |## 九、总结| 通信方式 | 适用场景 | 协议 | 特点 ||---------|---------|------|------|| HTTP | REST API、文件上传 | HTTP/HTTPS | 请求-响应,简单易用 || WebSocket | 即时通讯、实时推送 | WS/WSS | 全双工,服务端推送 || Socket | 自定义协议、高性能 | TCP/UDP | 底层控制,灵活 |> 参考文档:华为开发者联盟 HarmonyOS 5.0.0 API 12 — 网络编程指南

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐