【鸿蒙心迹】网络请求与证书校验实战:从HTTP到WebSocket的全链路拆解

摘要:本文围绕 HarmonyOS 7(API 26)的网络能力展开,系统讲解鸿蒙网络体系的三层架构——权限管控、证书校验与流量管理。全文分三层递进:先建立对 HTTP、WebSocket、SSE 三种通信方式的整体认知与选型判断;再深入 HTTPS 证书校验流程、三个校验维度、自定义证书校验与请求优先级等原理;最后通过 HTTP GET/POST、文件上传、WebSocket 长连接、自签名证书处理四个实战场景给出可运行代码,并附踩坑排错表与最佳实践清单。适合有 ArkTS 基础、希望打通鸿蒙网络通信全链路的开发者阅读。

网络请求是几乎所有应用的基础能力。HarmonyOS 7的网络体系在API 26上做了重要升级——新增了证书校验自定义、HTTP/2支持增强、WebSocket连接管理等能力。我第一次做鸿蒙网络开发时,以为就是用fetch或axios发请求,深入才发现鸿蒙的网络体系是"权限管控+证书校验+流量管理"的三层架构。最让人头疼的是HTTPS证书校验——自签名证书在开发环境一直报错,生产环境的证书校验配置又容易遗漏。

如果你有ArkTS开发基础,想让你的应用正确进行网络通信,但对鸿蒙网络体系不熟悉,这篇正好适合你。读完后你会知道:HTTP请求的完整流程、HTTPS证书校验机制、WebSocket长连接管理。

本文分三层来讲:第一层建立对网络体系的整体认知;第二层拆解证书校验和请求优化原理;第三层是完整的实战落地和踩坑排错。

入门认知:鸿蒙网络体系到底"网"了什么

一句话定义

鸿蒙网络体系是系统提供的网络通信能力——通过HTTP模块发起请求、通过WebSocket模块维持长连接、通过证书校验保障通信安全,所有网络访问需要声明权限并在系统管控下进行。

打个比方:传统网络开发就像自己开车——想去哪去哪;鸿蒙网络体系就像网约车——需要注册(权限声明)、需要验证司机(证书校验)、行程可追踪(流量管理)。

HTTP vs WebSocket vs SSE

对比维度HTTPWebSocketSSE
通信模式请求-响应双向全双工服务端推送
连接生命周期短连接(每次新建)长连接(持续保持)长连接
适用场景API调用、文件下载即时聊天、实时协作消息推送、数据流
数据格式任意任意文本
鸿蒙支持http模块webSocket模块不直接支持

表1:三种网络通信方式对比

全景图示

网络体系

HTTP请求

WebSocket长连接

安全校验

http.createHttp

请求配置

响应处理

webSocket.createWebSocket

连接管理

消息收发

权限声明

证书校验

CA证书配置

图2:网络体系架构

网络权限声明

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

适用边界

HTTP适合:API调用、文件上传下载、一次性数据获取。WebSocket适合:即时聊天、实时协作、股票行情等需要双向实时通信的场景。两者都不适合:不需要网络的本地操作。

下面用一张决策图帮你快速判断该选哪种通信方式:

否

是

否

是

是

否

需要网络通信的场景

是否需要服务端主动推送

是否一次性获取数据

HTTP 请求

HTTP 轮询(不推荐)

是否需要双向通信

WebSocket 长连接

SSE(鸿蒙不直接支持)

进阶原理:证书校验与请求优化

HTTPS证书校验流程

ServerHttpModuleAppServerHttpModuleAppalt[证书校验通过][证书校验失败]发起HTTPS请求TLS握手返回服务器证书校验证书链(CA验证)校验域名匹配校验有效期发送请求返回响应抛出证书错误

图3:HTTPS证书校验流程

证书校验的三个维度

校验维度说明失败原因
证书链验证服务器证书必须由受信任CA签发自签名证书、CA不在信任列表
域名匹配证书中的域名必须与请求域名一致证书域名不匹配
有效期证书必须在有效期内证书过期

表2:证书校验三个维度

自定义证书校验

API 26支持自定义证书校验逻辑,用于开发环境自签名证书或企业内部CA:

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

const httpRequest = http.createHttp();

// 自定义证书校验
httpRequest.on('certificateDataReceive', (certData: ArrayBuffer) => {
  // 自定义校验逻辑
  // 返回true表示信任该证书,返回false表示拒绝
  return true;
});

HTTP请求配置

const httpRequest = http.createHttp();

const options: http.HttpRequestOptions = {
  method: http.RequestMethod.GET,
  header: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token_value'
  },
  expectDataType: http.HttpDataType.STRING,
  usingCache: true,
  priority: http.RequestPriority.HIGH,
  connectTimeout: 5000,
  readTimeout: 5000,
  usingProtocol: http.HttpProtocol.HTTP2  // 优先使用HTTP/2
};

请求优先级

优先级说明适用场景
HIGH高优先级,优先调度用户交互触发的请求
MEDIUM中优先级一般业务请求
LOW低优先级后台预加载、统计上报

表3:请求优先级

请求从发起到完成的完整生命周期如下:

http.createHttp()

设置method/header/timeout

request()

HTTPS协议

校验通过

校验失败

收到数据

超时

destroy()

destroy()

创建请求对象

配置参数

发起请求

TLS握手

证书校验

发送数据

请求失败

等待响应

解析响应

销毁对象

实战落地:完整的网络开发流程

场景一:HTTP GET/POST请求

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

async function httpGet(url: string): Promise<string> {
  const httpRequest = http.createHttp();
  try {
    const response = await httpRequest.request(url, {
      method: http.RequestMethod.GET,
      expectDataType: http.HttpDataType.STRING,
      connectTimeout: 5000,
      readTimeout: 5000
    });
    
    if (response.responseCode === 200) {
      return response.result as string;
    } else {
      throw new Error(`HTTP ${response.responseCode}`);
    }
  } finally {
    httpRequest.destroy();
  }
}

async function httpPost(url: string, body: object): Promise<string> {
  const httpRequest = http.createHttp();
  try {
    const response = await httpRequest.request(url, {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'application/json' },
      extraData: JSON.stringify(body),
      expectDataType: http.HttpDataType.STRING,
      connectTimeout: 5000,
      readTimeout: 10000
    });
    
    if (response.responseCode === 200) {
      return response.result as string;
    } else {
      throw new Error(`HTTP ${response.responseCode}`);
    }
  } finally {
    httpRequest.destroy();
  }
}

场景二:文件上传

async function uploadFile(url: string, filePath: string): Promise<string> {
  const httpRequest = http.createHttp();
  try {
    const response = await httpRequest.request(url, {
      method: http.RequestMethod.POST,
      header: { 'Content-Type': 'multipart/form-data' },
      extraData: {
        filePath: filePath,
        name: 'file',
        fileName: 'upload.jpg'
      },
      expectDataType: http.HttpDataType.STRING,
      connectTimeout: 10000,
      readTimeout: 30000
    });
    return response.result as string;
  } finally {
    httpRequest.destroy();
  }
}

场景三:WebSocket长连接

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

let ws: webSocket.WebSocket | null = null;

async function connectWebSocket(url: string): Promise<void> {
  ws = webSocket.createWebSocket();
  
  // 注册消息回调
  ws.on('message', (err, data) => {
    if (!err) {
      console.info(`收到消息: ${data}`);
    }
  });
  
  // 注册关闭回调
  ws.on('close', (err, data) => {
    console.info('WebSocket已关闭');
  });
  
  // 注册错误回调
  ws.on('error', (err) => {
    console.error(`WebSocket错误: ${err.code}`);
  });
  
  // 建立连接
  await ws.connect(url, {
    header: { 'Authorization': 'Bearer token_value' }
  });
  console.info('WebSocket连接成功');
}

async function sendWebSocketMessage(msg: string): Promise<void> {
  if (ws) {
    await ws.send(msg);
  }
}

async function closeWebSocket(): Promise<void> {
  if (ws) {
    await ws.close({ code: 1000, reason: 'normal close' });
    ws = null;
  }
}

WebSocket 长连接的状态流转与事件回调关系如下:

on('message'/'close'/'error')

connect()

连接成功

握手失败

send()/on('message')

close()

on('close')

未连接

注册回调

连接中

已连接

连接失败

关闭中

已关闭

场景四:开发环境自签名证书处理

async function requestWithSelfSignedCert(url: string): Promise<string> {
  const httpRequest = http.createHttp();
  
  // 开发环境:信任自签名证书
  httpRequest.on('certificateDataReceive', (certData: ArrayBuffer) => {
    console.warn('收到自签名证书,开发环境自动信任');
    return true;  // 仅开发环境使用!生产环境必须移除
  });
  
  try {
    const response = await httpRequest.request(url, {
      method: http.RequestMethod.GET,
      expectDataType: http.HttpDataType.STRING
    });
    return response.result as string;
  } finally {
    httpRequest.destroy();
  }
}

踩坑排错

问题原因解决方案
请求失败报权限拒绝未声明INTERNET权限module.json5添加ohos.permission.INTERNET
HTTPS请求报证书错误证书不在信任列表生产环境配置正确CA,开发环境用自定义校验
请求超时connectTimeout/readTimeout过短根据网络环境调整超时时间
WebSocket连接后收不到消息on(‘message’)注册时机晚先注册回调再connect
HTTP/2不生效服务端不支持HTTP/2usingProtocol设为HTTP1_1
请求内存泄漏httpRequest未destroy每次请求后必须调用destroy
并发请求过多被限流同时发起大量请求控制并发量,使用请求队列

表4:常见踩坑与解决方案

最佳实践清单

  1. 每次请求后必须destroy — httpRequest对象不复用,不destroy会导致内存泄漏
  2. 生产环境不要信任自签名证书 — certificateDataReceive回调只在开发环境返回true
  3. WebSocket先注册回调再connect — connect之前注册所有事件回调
  4. 合理设置超时时间 — connectTimeout 5秒、readTimeout根据业务调整
  5. 使用HTTP/2提升性能 — 服务端支持时优先使用HTTP/2,多路复用减少连接数
  6. 请求优先级分级 — 用户交互请求用HIGH,后台请求用LOW
  7. WebSocket在aboutToDisappear中关闭 — 页面销毁时关闭连接,避免泄漏

最后用一张图串起整个网络开发流程,方便回顾:

是

否

200

非200

声明 INTERNET 权限

创建请求对象

是否 HTTPS

证书校验

直接发送

发送请求

响应状态码

解析数据

异常处理

destroy 释放

记录日志/上报

Logo

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

更多推荐