HarmonyOS APP《画伴梦工厂》开发第18篇:HTTP 网络请求——@kit.NetworkKit 全解析
第3.1篇:HTTP 网络请求——@kit.NetworkKit 全解析
系列:鸿蒙 AI 服务与网络集成篇
难度:⭐⭐ 进阶
前置知识:1.2 ArkUI 声明式 UI 基础
涉及源文件:products/default/src/main/ets/services/AIGenerationService.ets

在"画伴梦工厂"中,所有 AI 能力的调用——文生图、图生视频、任务状态查询、视频文件下载——都离不开网络请求。HarmonyOS 提供了 @kit.NetworkKit 作为标准的 HTTP 网络通信解决方案,它封装了从会话创建、请求配置、响应处理到资源释放的完整链路。
本文将以 AIGenerationService.ets 中的真实代码为线索,全面解析 @kit.NetworkKit 的核心用法。
一、@kit.NetworkKit 概述
@kit.NetworkKit 是 HarmonyOS 提供的原生网络通信 Kit,其核心模块是 http 模块。它提供了基于 HTTP/HTTPS 协议的网络请求能力,支持:
- 会话管理:通过
http.createHttp()创建独立的 HTTP 会话 - 多种请求方法:GET、POST、PUT、DELETE 等
- 灵活的请求配置:自定义 Header、请求体、超时时间、期望响应类型
- 完整的响应信息:状态码、响应头、响应体
- 资源生命周期管理:显式销毁会话以释放 native 资源
在项目中引入方式十分简洁:
import { http } from '@kit.NetworkKit';
@kit.NetworkKit 是鸿蒙的元能力 Kit,无需在 oh-package.json5 中额外声明依赖,开箱即用。
二、http.createHttp——创建 HTTP 会话
http.createHttp() 是使用 @kit.NetworkKit 的入口。它创建一个 HttpRequest 对象,代表一个独立的 HTTP 会话(Session)。
基本用法
const request = http.createHttp();
每次调用 createHttp 都会返回一个新会话实例。这个会话可以被多次复用来发起请求,不需要每次请求都重新创建。
会话的作用域
在 AIGenerationService.ets 中,每个需要网络请求的私有方法都会在方法内部创建自己的会话:
private static async createSeedreamImage(prompt: string): Promise<string> {
const request = http.createHttp(); // 创建会话
try {
// ... 发起请求
} finally {
request.destroy(); // 销毁会话
}
}
这种"方法内创建、销毁"的模式是最安全的使用方式,确保每个会话的生命周期可控,避免资源泄漏。
三、Request 配置——method、header、extraData
http.HttpRequestOptions 是请求配置的核心接口。来看项目中一个典型的 POST 请求配置:
const options: http.HttpRequestOptions = {
method: http.RequestMethod.POST,
expectDataType: http.HttpDataType.STRING,
connectTimeout: 30000,
readTimeout: 90000,
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + ARK_API_KEY
},
extraData: JSON.stringify(requestBody)
};
const response = await request.request(ARK_IMAGE_API_URL, options);
3.1 method——请求方法
通过 http.RequestMethod 枚举指定 HTTP 方法。项目中主要使用了两种:
| 方法 | 使用场景 | 示例 |
|---|---|---|
http.RequestMethod.POST |
提交任务、发送数据(文生图、图生视频任务创建) | createSeedreamImage、createImg2VideoTask |
http.RequestMethod.GET |
查询任务状态、下载文件 | querySeedanceTask、downloadVideo |
3.2 header——请求头
请求头通过普通 JavaScript 对象配置。项目中根据接口需求定义了两种 Header 类型:
interface ArkHeaders {
'Content-Type': string;
'Authorization': string;
}
interface JsonHeaders {
'Content-Type': string;
}
ArkHeaders(用于火山引擎 Ark API):
const headers: ArkHeaders = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + ARK_API_KEY
};
Content-Type: application/json声明请求体为 JSON 格式Authorization: Bearer <token>携带 API 密钥进行身份认证
JsonHeaders(用于自建中间件服务):
const headers: JsonHeaders = {
'Content-Type': 'application/json'
};
自建中间件不需要 API 密钥,因此仅需声明内容类型。
3.3 extraData——请求体
extraData 用于传递请求体数据。需要注意:extraData 的类型必须与 header 中的 Content-Type 保持一致。
当 Content-Type 为 application/json 时,extraData 必须是已经序列化的 JSON 字符串:
// 先构造请求体对象
const body: ImageGenerationRequest = {
model: 'doubao-seedream-4-0-250828',
prompt: prompt,
response_format: 'url',
size: '1024x1024',
guidance_scale: 2.5,
watermark: true
};
// 序列化为 JSON 字符串后传入 extraData
extraData: JSON.stringify(body)
这是一个常见的易错点。许多初学者会直接将 JavaScript 对象传入 extraData,但 HarmonyOS 的 HttpRequest 要求开发者自行完成序列化。这也是项目中总是先写 JSON.stringify() 再传入的原因。
四、超时配置——ConnectTimeout / ReadTimeout
网络请求的两个核心超时参数,在项目中针对不同场景做了精细的差异化配置:
ConnectTimeout(连接超时)
指从发起请求到建立 TCP 连接的最长等待时间。项目中对所有请求统一设置为 30000ms(30 秒):
connectTimeout: 30000
30 秒是一个合理的默认值——既不会让用户在弱网环境下等待过久,也不会因为过短而在正常慢速网络上频繁失败。
ReadTimeout(读取超时)
指建立连接后等待服务器返回数据的最大时间。不同接口的耗时差异很大,项目针对不同场景配置了不同的读取超时:
| 场景 | 超时时间 | 常量 | 说明 |
|---|---|---|---|
| 文生图请求 | 90 秒 | 90000 |
图片生成通常较快 |
| 图生视频任务创建 | 180 秒 | SEEDANCE_CREATE_TIMEOUT_MS |
首次提交可能稍慢 |
| 任务状态查询 | 240 秒 | SEEDANCE_QUERY_TIMEOUT_MS |
轮询查询等待结果 |
| 视频文件下载 | 240 秒 | SEEDANCE_DOWNLOAD_TIMEOUT_MS |
大文件下载需要更长等待 |
// 短请求——文生图
readTimeout: 90000
// 长请求——视频下载
readTimeout: SEEDANCE_DOWNLOAD_TIMEOUT_MS // 240000ms
超时设计原则:ConnectTimeout 可以统一,但 ReadTimeout 必须根据接口的实际耗时特点差异化配置。AI 推理类接口通常需要较长的等待时间,因此项目中大多数 ReadTimeout 设置在 90 秒以上。
五、响应处理——responseCode 与 result
请求返回的 http.HttpResponse 对象包含两个核心字段:
| 字段 | 类型 | 说明 |
|---|---|---|
responseCode |
number |
HTTP 状态码(200、400、500 等) |
result |
string | object | ArrayBuffer |
响应体内容,类型由 expectDataType 决定 |
5.1 状态码校验
项目中对所有 HTTP 响应都进行了严格的状态码校验:
if (response.responseCode < 200 || response.responseCode >= 300) {
throw new Error('图片生成任务创建失败:' + response.responseCode.toString());
}
这段代码使用了范围判断而非简单的 !== 200,好处是:
- 自动识别所有 2xx 成功状态码(200、201、204 等),兼容性更好
- 将 3xx 重定向、4xx 客户端错误、5xx 服务端错误统一归为失败
5.2 响应体解析
response.result 的类型由请求配置中的 expectDataType 决定。当设为 http.HttpDataType.STRING 时,result 为字符串:
const responseText = response.result.toString();
const responseBody = JSON.parse(responseText) as ImageGenerationResponse;
重要:即使 expectDataType 已指定为 STRING,代码中仍然调用了 .toString()。这是一种防御性编程习惯,确保即使底层行为发生变化,也能获得字符串以供 JSON.parse 使用。
5.3 业务错误处理
HTTP 状态码正常(2xx)不代表业务成功。项目在状态码校验之后,还会检查响应体中的业务错误字段:
// 检查 API 返回的业务错误
if (responseBody.error && responseBody.error.message) {
throw new Error(responseBody.error.message);
}
// 检查数据完整性
if (!responseBody.data || responseBody.data.length === 0) {
throw new Error('图片生成接口未返回图片');
}
这种双层校验模式——先校验 HTTP 协议层(responseCode),再校验业务逻辑层(response body)——是可靠网络通信的基础。
六、Session 复用与销毁
6.1 为什么必须销毁
http.createHttp() 创建的会话在 native 层持有资源(socket 连接、内存缓冲区等)。如果不主动销毁,可能会导致资源泄漏。项目中的所有 HTTP 请求都遵循了 try-finally-destroy 模式:
private static async createSeedreamImage(prompt: string): Promise<string> {
const request = http.createHttp();
try {
// ... 请求处理
return imageData.url;
} finally {
request.destroy(); // 无论成功或异常,都确保销毁
}
}
finally 块确保无论请求成功还是抛出异常,destroy() 都会被执行。这是防止资源泄漏的最可靠模式。
6.2 长时间轮询中的会话复用
在 pollImg2VideoTask 方法中,项目采用了一个不同的策略——每次轮询都创建新的会话:
private static async queryImg2VideoTask(taskId: string): Promise<Img2VideoStatusResponse> {
const request = http.createHttp();
try {
// ... 发起单个查询请求
} finally {
request.destroy();
}
}
轮询循环(每 5 秒一次)并不直接创建会话,而是调用 queryImg2VideoTask 这个独立方法,由该方法自行创建和销毁会话。这种设计的好处是:
- 避免连接泄漏——即使某次轮询异常中断,该次会话已被 finally 清理
- 避免连接过期——长时间复用的连接可能被服务端断开,每次新建更可靠
- 代码职责清晰——每个方法只负责自己的会话生命周期
6.3 何时可以复用
会话复用的典型场景是短时间内连续发送多个请求到同一服务器。例如:
const request = http.createHttp();
try {
const r1 = await request.request(urlA, optionsA);
const r2 = await request.request(urlB, optionsB);
const r3 = await request.request(urlC, optionsC);
} finally {
request.destroy();
}
项目中没有采用这种模式,而是选择了"每次请求独立会话"的方式。对于与不同 API 服务(Ark 火山引擎、自建中间件)交互的场景,这种方式更加安全可靠。
七、ARRAY_BUFFER 响应类型与文件下载
对于图片和视频等二进制文件的下载,需要将 expectDataType 设置为 http.HttpDataType.ARRAY_BUFFER:
7.1 下载配置
const response = await request.request(remoteUrl, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 30000,
readTimeout: SEEDANCE_DOWNLOAD_TIMEOUT_MS // 240 秒
});
当 expectDataType 为 ARRAY_BUFFER 时,response.result 的类型变为 ArrayBuffer,需要通过 as 断言获取:
const videoBuffer = response.result as ArrayBuffer;
7.2 保存到本地文件
获取到 ArrayBuffer 后,配合 @kit.CoreFileKit 的 fileIo 模块即可写入本地文件:
const context = getContext() as common.UIAbilityContext;
const path = context.filesDir + '/seedance_' + taskId + '.mp4';
const file = fileIo.openSync(path, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE);
try {
fileIo.writeSync(file.fd, videoBuffer);
} finally {
fileIo.closeSync(file);
}
return 'file://' + path;
在这个过程中,http 模块只负责"下载到内存",fileIo 模块负责"从内存写入磁盘"。两者分工明确:
| 模块 | 职责 | 对应方法 |
|---|---|---|
@kit.NetworkKit HTTP |
从网络接收二进制数据 | request() + ARRAY_BUFFER |
@kit.CoreFileKit fileIo |
将内存数据写入文件 | fileIo.openSync → writeSync → closeSync |
7.3 图片下载的复用
项目中 downloadImageAsArrayBuffer 方法也同样使用了 ARRAY_BUFFER 模式来下载远程图片:
private static async downloadImageAsArrayBuffer(url: string): Promise<ArrayBuffer> {
const request = http.createHttp();
try {
const response = await request.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER,
connectTimeout: 30000,
readTimeout: 90000
});
if (response.responseCode < 200 || response.responseCode >= 300) {
throw new Error('图片下载失败:' + response.responseCode.toString());
}
return response.result as ArrayBuffer;
} finally {
request.destroy();
}
}
注意这里将 ArrayBuffer 直接作为方法返回值,由调用方决定如何处理(压缩、编码、保存等),体现了职责分离的设计思想。
八、最佳实践总结
8.1 请求模式对比
| 模式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 单会话单请求(项目采用) | 生命周期清晰、无泄漏风险 | 每次请求有创建开销 | 与多个不同 API 服务交互 |
| 单会话多请求 | 连接复用、性能更优 | 需自行管理生命周期 | 连续请求同一服务器 |
8.2 超时配置对照表
| 参数 | 推荐值 | 配置位置 |
|---|---|---|
connectTimeout |
30000(30 秒) | http.HttpRequestOptions |
readTimeout(普通 API) |
90000(90 秒) | http.HttpRequestOptions |
readTimeout(AI 推理) |
180000240000(34 分钟) | http.HttpRequestOptions |
8.3 安全编码清单
- always destroy:无论成功还是异常,
finally块中执行request.destroy() - 序列化先行:
extraData接收字符串,使用JSON.stringify序列化对象 - 状态码范围校验:用
responseCode < 200 || responseCode >= 300而非!== 200 - 业务错误二次校验:HTTP 2xx 不等于业务成功,需解析响应体中的
error字段 - 二进制文件用 ARRAY_BUFFER:下载图片或视频时显式指定
expectDataType: http.HttpDataType.ARRAY_BUFFER - ConnectTimeout 统一,ReadTimeout 差异化:根据接口耗时特征分别配置
8.4 完整流程时序
以一次文生图调用为例,展示完整的 HTTP 请求生命周期:
调用方(generateImage)
│
▼
createSeedreamImage(prompt)
│
├── request = http.createHttp() 创建会话
│
├── request.request(url, options) 发起 POST 请求
│ ├── connectTimeout: 30000 等待连接建立
│ ├── readTimeout: 90000 等待响应返回
│ └── extraData: JSON.stringify 请求体序列化
│
├── response.responseCode 校验 检查 HTTP 状态码
├── responseBody.error 校验 检查业务错误
├── response.data[0] 校验 检查数据完整性
│
└── finally → request.destroy() 销毁会话
总结
本文通过"画伴梦工厂"中 AIGenerationService.ets 的真实代码,全面解析了 @kit.NetworkKit 的 HTTP 网络请求能力:
| 知识点 | 实现方式 |
|---|---|
| 创建 HTTP 会话 | http.createHttp() |
| POST 请求配置 | method + header + extraData + JSON.stringify |
| GET 请求配置 | method: http.RequestMethod.GET + expectDataType |
| 超时控制 | connectTimeout + readTimeout 差异化配置 |
| 响应处理 | responseCode 范围校验 + 业务错误二次校验 |
| 二进制下载 | expectDataType: ARRAY_BUFFER + fileIo.writeSync |
| 资源释放 | try-finally 模式中的 request.destroy() |
下一篇: 第 3.2 篇将深入 火山引擎 Seedream 文生图 API 对接,基于本文的 HTTP 请求基础,拆解请求体组装、响应解析和错误处理的完整实战。
参考源码
本文所有代码均来自项目文件:
products/default/src/main/ets/services/AIGenerationService.ets— AI 服务核心,包含完整的 HTTP 请求封装、多种超时策略、ARRAY_BUFFER 下载、以及 try-finally-destroy 资源管理模式
更多推荐


所有评论(0)