【鸿蒙心迹】网络请求与证书校验实战:从HTTP到WebSocket的全链路拆解
【鸿蒙心迹】网络请求与证书校验实战:从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
| 对比维度 | HTTP | WebSocket | SSE |
|---|---|---|---|
| 通信模式 | 请求-响应 | 双向全双工 | 服务端推送 |
| 连接生命周期 | 短连接(每次新建) | 长连接(持续保持) | 长连接 |
| 适用场景 | API调用、文件下载 | 即时聊天、实时协作 | 消息推送、数据流 |
| 数据格式 | 任意 | 任意 | 文本 |
| 鸿蒙支持 | http模块 | webSocket模块 | 不直接支持 |
表1:三种网络通信方式对比
全景图示
图2:网络体系架构
网络权限声明
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
}
适用边界
HTTP适合:API调用、文件上传下载、一次性数据获取。WebSocket适合:即时聊天、实时协作、股票行情等需要双向实时通信的场景。两者都不适合:不需要网络的本地操作。
下面用一张决策图帮你快速判断该选哪种通信方式:
进阶原理:证书校验与请求优化
HTTPS证书校验流程
图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 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 长连接的状态流转与事件回调关系如下:
场景四:开发环境自签名证书处理
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/2 | usingProtocol设为HTTP1_1 |
| 请求内存泄漏 | httpRequest未destroy | 每次请求后必须调用destroy |
| 并发请求过多被限流 | 同时发起大量请求 | 控制并发量,使用请求队列 |
表4:常见踩坑与解决方案
最佳实践清单
- 每次请求后必须destroy — httpRequest对象不复用,不destroy会导致内存泄漏
- 生产环境不要信任自签名证书 — certificateDataReceive回调只在开发环境返回true
- WebSocket先注册回调再connect — connect之前注册所有事件回调
- 合理设置超时时间 — connectTimeout 5秒、readTimeout根据业务调整
- 使用HTTP/2提升性能 — 服务端支持时优先使用HTTP/2,多路复用减少连接数
- 请求优先级分级 — 用户交互请求用HIGH,后台请求用LOW
- WebSocket在aboutToDisappear中关闭 — 页面销毁时关闭连接,避免泄漏
最后用一张图串起整个网络开发流程,方便回顾:
更多推荐



所有评论(0)