HarmonyOS 网络编程实战:HTTP、WebSocket 与 Socket 通信详解

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 --- 网络编程指南

相关推荐
逻极1 小时前
HTTP/HTTPS 协议从入门到精通:从原理到性能提升400%的完整路径(协议优化实战)
网络协议·http·性能优化·https·tls
努力的lpp1 小时前
渗透主流工具完整参数手册(sqlmap、Nmap、Hydra、Dirsearch、Xray)
javascript·网络协议·测试工具·安全·http·工具
茶乡浪子2 小时前
基于IPv4网络分布式网关动态VXLAN配置示例
网络·数据中心·vxlan·华为vxlan·华为数据中心网络·bgp evpn·数据中心网络工程师
风满城332 小时前
鸿蒙原生应用实战(二):数独游戏核心逻辑开发 — 棋盘渲染与交互
harmonyos
李白的天不白3 小时前
http https
网络协议·http·https
酣大智3 小时前
IS-IS路由协议
网络·路由·isis
果丁智能10 小时前
智能锁赋能网约房民宿数字化管控:身份核验+远程授权,筑牢安全防线、降本增效
网络·数据库·人工智能·安全·智能家居
wp123_110 小时前
射频前端无源器件观察:Coilcraft WBC1-1TLC vs TONEVEE WBT1-1CT 国产与进口巴伦变压器的技术博弈
网络
风满城3311 小时前
【鸿蒙原生应用开发实战】第五篇:项目总结——ArkTS 最佳实践与从 MVP 到生产的升级之路
华为·harmonyos