HarmonyOS 网络请求:HTTP 客户端从入门到实战


一、引言
网络请求是现代应用开发的核心能力。无论是登录认证、数据拉取、文件上传,还是与云端服务交互,都离不开 HTTP 协议。HarmonyOS NEXT 提供了功能强大的 @ohos.net.http 模块(通过 @kit.NetworkKit 访问),支持 GET、POST、PUT、DELETE 等多种请求方法,以及超时控制、请求头定制、响应解析等完整能力。
本文将以一个科技蓝渐变风格的网络请求演示页面为主线,从零开始讲解 HarmonyOS HTTP 客户端的完整使用流程。全文包含大量代码示例和逐行说明,帮助读者彻底掌握网络请求技术。
二、HTTP 协议基础
2.1 HTTP 请求与响应模型
HTTP(超文本传输协议)采用"请求-响应"模型:
- 客户端发起请求:客户端(如 HarmonyOS 应用)向服务器发送 HTTP 请求。
- 服务器处理请求:服务器根据请求内容进行业务处理。
- 服务器返回响应:服务器将处理结果以 HTTP 响应返回给客户端。
- 客户端解析响应:客户端解析响应内容并展示给用户。
2.2 HTTP 请求的组成
一个完整的 HTTP 请求由以下部分组成:
| 组成 | 说明 | 示例 |
|---|---|---|
| 请求行 | 请求方法 + URL + 协议版本 | GET /get HTTP/1.1 |
| 请求头 | 键值对形式的元信息 | Content-Type: application/json |
| 请求体 | 携带的业务数据 | {“name”: “AtomCode”} |
2.3 HTTP 响应状态码
HTTP 响应状态码由三位数字组成,表示请求的处理结果。常见状态码分类如下:
| 状态码 | 含义 | 说明 |
|---|---|---|
| 200 | OK | 请求成功 |
| 301 | Moved Permanently | 永久重定向 |
| 302 | Found | 临时重定向 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未授权访问 |
| 403 | Forbidden | 禁止访问 |
| 404 | Not Found | 资源不存在 |
| 500 | Internal Server Error | 服务器内部错误 |
| 502 | Bad Gateway | 网关错误 |
| 503 | Service Unavailable | 服务不可用 |
三、HarmonyOS HTTP 模块概览
3.1 模块导入
import { http } from '@kit.NetworkKit';
代码说明:
@kit.NetworkKit 是 HarmonyOS 网络能力套件,http 是其子模块,提供了 HTTP 客户端的全部能力。
3.2 核心类与方法
HarmonyOS HTTP 模块的核心 API 如下:
| API | 说明 |
|---|---|
http.createHttp() |
创建 HTTP 请求对象 |
httpRequest.request() |
发起网络请求 |
httpRequest.destroy() |
销毁请求对象,释放资源 |
http.RequestMethod |
请求方法枚举(GET/POST/PUT/DELETE 等) |
http.ResponseCode |
响应状态码枚举 |
四、实战代码:完整的网络请求页面
下面我们实现一个功能完整的网络请求演示页面,支持 GET 和 POST 两种请求方式,并展示响应结果和状态码速查表。
4.1 定义数据结构
interface StatusRow {
code: string;
meaning: string;
color: string;
}
代码说明:
StatusRow 接口描述状态码表格中的一行数据:
code:HTTP 状态码,如 “200”、“404”。meaning:状态码含义说明。color:该状态码对应的展示颜色,用于视觉区分成功、警告、错误等不同类别。
4.2 组件状态定义
@Entry
@Component
struct HttpPage {
@State statusRows: StatusRow[] = [
{ code: '200', meaning: 'OK 请求成功', color: '#2ED573' },
{ code: '301', meaning: '永久重定向', color: '#FFA502' },
{ code: '400', meaning: '请求参数错误', color: '#FF6348' },
{ code: '401', meaning: '未授权访问', color: '#FF4757' },
{ code: '404', meaning: '资源不存在', color: '#FF4757' },
{ code: '500', meaning: '服务器内部错误', color: '#FF6B81' }
];
@State result: string = '点击下方按钮发起请求';
@State loading: boolean = false;
代码说明:
@State statusRows:状态码表格数据,使用@State装饰以便 UI 响应式更新。@State result:请求结果展示文本。@State loading:请求进行中的标志,用于控制按钮文字和防止重复请求。
4.3 发起 GET 请求
async doGet(): Promise<void> {
this.loading = true;
this.result = '请求中...';
const httpRequest = http.createHttp();
try {
const resp = await httpRequest.request('https://httpbin.org/get', {
method: http.RequestMethod.GET,
connectTimeout: 10000,
readTimeout: 10000
});
if (resp.responseCode === 200) {
this.result = `状态码: ${resp.responseCode}\n${JSON.stringify(resp.result)}`;
} else {
this.result = `状态码: ${resp.responseCode}`;
}
} catch (e) {
this.result = `请求失败: ${JSON.stringify(e)}`;
} finally {
httpRequest.destroy();
this.loading = false;
}
}
代码说明:
doGet 方法演示了完整的 GET 请求流程:
-
设置加载状态:
this.loading = true标记请求开始,UI 上的按钮会显示"请求中…"。 -
创建请求对象:
http.createHttp()创建 HTTP 请求对象。每个请求都应该创建独立的请求对象,避免状态污染。 -
发起请求:
httpRequest.request(url, options)是核心方法,参数说明如下:- 第一个参数:请求的 URL 地址。这里使用
https://httpbin.org/get,httpbin 是一个免费的 HTTP 测试服务,会原样返回请求信息。 - 第二个参数是请求配置对象:
method:请求方法,这里指定为http.RequestMethod.GET。connectTimeout:连接超时时间(毫秒),超过该时间未建立连接则报错。readTimeout:读取超时时间(毫秒),超过该时间未收到数据则报错。
- 第一个参数:请求的 URL 地址。这里使用
-
处理响应:
resp.responseCode:响应状态码,200 表示成功。resp.result:响应内容,可能是 JSON 字符串、文本或 ArrayBuffer。- 成功时用
JSON.stringify将响应对象格式化为可读文本。
-
异常处理:
catch块捕获网络异常(如超时、断网、DNS 解析失败),将错误信息展示给用户。 -
资源释放:
finally块中调用httpRequest.destroy()销毁请求对象,释放网络资源。这是非常重要的,如果不销毁会导致资源泄漏。 -
恢复状态:
this.loading = false标记请求结束。
4.4 发起 POST 请求
async doPost(): Promise<void> {
this.loading = true;
this.result = 'POST 请求中...';
const httpRequest = http.createHttp();
try {
const resp = await httpRequest.request('https://httpbin.org/post', {
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify({ name: 'AtomCode', topic: 'HarmonyOS' }),
connectTimeout: 10000,
readTimeout: 10000
});
this.result = `状态码: ${resp.responseCode}\n${JSON.stringify(resp.result)}`;
} catch (e) {
this.result = `请求失败: ${JSON.stringify(e)}`;
} finally {
httpRequest.destroy();
this.loading = false;
}
}
代码说明:
doPost 方法与 GET 的关键区别在于请求配置:
-
请求方法:
method: http.RequestMethod.POST指定使用 POST 方法。 -
请求头定制:
header: { 'Content-Type': 'application/json' }设置请求头,告诉服务器请求体是 JSON 格式。服务器会根据 Content-Type 正确解析请求体。 -
请求体数据:
extraData指定请求体内容。这里我们将一个对象序列化为 JSON 字符串。注意:extraData的类型取决于 Content-Type:- 如果是
application/json,需要传入 JSON 字符串。 - 如果是
application/x-www-form-urlencoded,需要传入表单格式的字符串(如key1=value1&key2=value2)。
- 如果是
4.5 构建 UI
build() {
Scroll() {
Column({ space: 16 }) {
// 顶部渐变区
Column() {
Text('HTTP')
.fontSize(12)
.fontColor('#B3E5FC')
.letterSpacing(8)
Text('网络请求')
.fontSize(26)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.margin({ top: 6 })
Text('http 模块 · GET / POST 实战')
.fontSize(12)
.fontColor('#B3E5FC')
.margin({ top: 6 })
}
.width('100%')
.padding({ top: 48, bottom: 32 })
.linearGradient({
angle: 135,
colors: [['#0F2027', 0], ['#203A43', 0.5], ['#2C5364', 1]]
})
代码说明:
顶部标题区使用 .linearGradient 设置线性渐变背景,形成科技蓝的视觉效果:
angle: 135:渐变方向角度,135 度表示从左上到右下。colors:渐变颜色数组,每个元素是[颜色, 位置]的元组,位置取值范围 0 到 1。- 这里使用三个颜色节点,形成从深黑蓝到青蓝的渐变过渡。
// 横向卡片区(Row 布局)
Row({ space: 12 }) {
Column({ space: 8 }) {
Text('GET')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#00D2FF')
Text('拉取数据\nhttpbin.org/get')
.fontSize(11)
.fontColor('#AAAAAA')
.textAlign(TextAlign.Center)
}
.layoutWeight(1)
.padding(16)
.backgroundColor('#1A2A3A')
.borderRadius(16)
.border({ width: 1, color: '#00D2FF55' })
Column({ space: 8 }) {
Text('POST')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#FF6B81')
Text('提交数据\nhttpbin.org/post')
.fontSize(11)
.fontColor('#AAAAAA')
.textAlign(TextAlign.Center)
}
.layoutWeight(1)
.padding(16)
.backgroundColor('#1A2A3A')
.borderRadius(16)
.border({ width: 1, color: '#FF6B8155' })
}
.width('100%')
代码说明:
横向卡片区使用 Row 水平布局,展示 GET 和 POST 两种请求方式的说明卡片:
- 每个卡片是一个
Column,包含方法名和说明文字。 .layoutWeight(1)让两个卡片平分宽度。- 卡片背景
#1A2A3A是深蓝灰色,与整体科技蓝风格统一。 .border设置 1 像素的彩色描边,GET 用青色(#00D2FF),POST 用粉色(#FF6B81),通过颜色区分请求类型。
// 渐变按钮
Button(this.loading ? '请求中...' : '发起 GET 请求')
.width('100%')
.height(48)
.fontSize(15)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.linearGradient({
angle: 90,
colors: [['#00D2FF', 0], ['#3A7BD5', 1]]
})
.borderRadius(24)
.shadow({ radius: 12, color: '#5500D2FF', offsetY: 4 })
.onClick(() => { this.doGet(); })
代码说明:
请求按钮采用渐变填充风格:
Button(this.loading ? '请求中...' : '发起 GET 请求'):根据loading状态动态显示按钮文字,请求中显示"请求中…",防止用户重复点击。.linearGradient:按钮背景使用青蓝渐变,与整体风格一致。.borderRadius(24):设置大圆角,形成胶囊按钮。.shadow:设置按钮阴影,radius是阴影模糊半径,color是阴影颜色(带透明度),offsetY是垂直偏移。阴影让按钮有悬浮感。
// 结果展示框
Column() {
Text('响应结果')
.fontSize(12)
.fontColor('#00D2FF')
.alignSelf(ItemAlign.Start)
Text(this.result)
.fontSize(12)
.fontColor('#E0E0E0')
.fontFamily('monospace')
.margin({ top: 8 })
.alignSelf(ItemAlign.Start)
}
.width('100%')
.padding(16)
.backgroundColor('#0D1B2A')
.borderRadius(12)
.border({ width: 1, color: '#1B3A5C' })
代码说明:
结果展示框用于显示请求响应:
- 背景色
#0D1B2A是深蓝黑色,模拟终端效果。 .fontFamily('monospace')使用等宽字体显示响应内容,增强代码感。.alignSelf(ItemAlign.Start)让内容左对齐。
// 状态码表格:带彩色标签
Column() {
Text('HTTP 状态码速查表')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.alignSelf(ItemAlign.Start)
.margin({ bottom: 8 })
ForEach(this.statusRows, (row: StatusRow) => {
Row({ space: 10 }) {
Text(row.code)
.fontSize(13)
.fontWeight(FontWeight.Bold)
.fontColor(row.color)
.width(56)
.textAlign(TextAlign.Center)
.padding({ top: 3, bottom: 3 })
.borderRadius(4)
.backgroundColor(`${row.color}22`)
Text(row.meaning)
.fontSize(13)
.fontColor('#CCCCCC')
.layoutWeight(1)
}
.width('100%')
.padding({ top: 10, bottom: 10 })
.border({ width: { bottom: 1 }, color: '#1B3A5C' })
})
}
.width('100%')
.padding(16)
.backgroundColor('#12263A')
.borderRadius(12)
代码说明:
状态码速查表是页面的核心表格:
- 每行包含状态码和含义说明。
- 状态码使用彩色标签展示:文字颜色为
row.color,背景为${row.color}22(在颜色后追加 “22” 表示 22% 透明度的十六进制颜色,这是 HarmonyOS 支持的颜色透明度简写)。 - 成功状态码(200)为绿色,警告(301)为橙色,错误(400+)为红色,通过颜色直观区分。
- 行与行之间用底部边框分隔,形成表格效果。
五、HTTP 请求完整配置详解
5.1 请求配置对象
request 方法的第二个参数是完整的请求配置,包含以下可选字段:
const options: http.HttpRequestOptions = {
method: http.RequestMethod.GET, // 请求方法
header: { // 请求头
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
extraData: '请求体数据', // 请求体
expectDataType: http.HttpDataType.STRING, // 期望响应类型
usingCache: true, // 是否使用缓存
priority: 1, // 请求优先级
connectTimeout: 60000, // 连接超时(毫秒)
readTimeout: 60000, // 读取超时(毫秒)
usingProtocol: http.HttpProtocol.HTTP1_1, // 协议版本
};
代码说明:
expectDataType:期望的响应数据类型,可选值包括STRING(字符串)、OBJECT(JSON 对象)、ARRAY_BUFFER(二进制数据)。设置正确的类型可以避免手动解析。usingCache:是否启用缓存,启用后相同请求会优先使用缓存。usingProtocol:HTTP 协议版本,默认 HTTP1_1,也可指定 HTTP2。
5.2 支持的所有请求方法
http.RequestMethod.OPTIONS // 查询服务器支持的方法
http.RequestMethod.GET // 获取资源
http.RequestMethod.HEAD // 获取响应头(无响应体)
http.RequestMethod.POST // 提交数据
http.RequestMethod.PUT // 更新资源
http.RequestMethod.DELETE // 删除资源
http.RequestMethod.TRACE // 回显请求(诊断用)
http.RequestMethod.CONNECT // 建立隧道连接
5.3 响应对象详解
const resp = await httpRequest.request(url, options);
// 响应状态码
const code = resp.responseCode;
// 响应头
const headers = resp.header;
// 响应数据(类型由 expectDataType 决定)
const data = resp.result;
// 原始响应数据(ArrayBuffer)
const raw = resp.result as ArrayBuffer;
// 响应内容类型
const contentType = resp.header['Content-Type'];
六、常见请求场景实战
6.1 携带 Token 的认证请求
async function fetchUserInfo(token: string): Promise<string> {
const httpRequest = http.createHttp();
try {
const resp = await httpRequest.request('https://api.example.com/user', {
method: http.RequestMethod.GET,
header: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
},
expectDataType: http.HttpDataType.OBJECT
});
if (resp.responseCode === 200) {
return JSON.stringify(resp.result);
}
return `请求失败: ${resp.responseCode}`;
} finally {
httpRequest.destroy();
}
}
6.2 表单提交
const httpRequest = http.createHttp();
const resp = await httpRequest.request('https://api.example.com/login', {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
extraData: 'username=admin&password=123456'
});
6.3 下载文件
const httpRequest = http.createHttp();
const resp = await httpRequest.request('https://example.com/file.zip', {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER
});
const buffer = resp.result as ArrayBuffer;
// 将 ArrayBuffer 写入文件(需要 fileIo 配合)
七、网络权限配置
在 HarmonyOS 中发起网络请求需要申请网络权限。在 module.json5 中添加:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
代码说明:
ohos.permission.INTERNET:网络访问权限,是发起 HTTP 请求的必需权限。- 如果应用需要访问网络状态,还需要申请
ohos.permission.GET_NETWORK_INFO权限。
八、最佳实践
8.1 统一封装请求工具
在实际项目中,建议将 HTTP 请求封装为统一工具类,便于管理和复用:
export class HttpUtil {
static async get<T>(url: string): Promise<T> {
const httpRequest = http.createHttp();
try {
const resp = await httpRequest.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.OBJECT
});
return resp.result as T;
} finally {
httpRequest.destroy();
}
}
}
8.2 超时处理
务必设置合理的超时时间,避免请求长时间挂起:
const resp = await httpRequest.request(url, {
connectTimeout: 10000, // 10 秒连接超时
readTimeout: 30000 // 30 秒读取超时
});
8.3 资源释放
每次请求完成后务必调用 destroy() 释放资源,推荐使用 try...finally 结构。
8.4 错误处理
网络请求可能失败的原因很多:断网、超时、DNS 解析失败、服务器错误等。建议对错误进行分类处理,给用户友好的提示。
九、常见问题
9.1 请求报错"no permission"
原因:没有在 module.json5 中配置 ohos.permission.INTERNET 权限。
解决:添加网络权限配置。
9.2 HTTPS 证书校验失败
原因:服务器证书不受信任。
解决:检查服务器证书是否有效;开发阶段可临时关闭证书校验(不推荐生产环境使用)。
9.3 请求结果类型不正确
原因:没有设置 expectDataType,或响应内容与期望类型不匹配。
解决:根据实际响应内容设置正确的 expectDataType。
十、总结
本文完整讲解了 HarmonyOS HTTP 网络请求的开发流程。我们实现了一个科技蓝渐变风格的网络请求演示页面,支持 GET 和 POST 两种请求方式,并详细解析了请求配置、响应处理、错误处理等核心知识点。
核心要点回顾:
- 使用
http.createHttp()创建请求对象,请求完成后必须destroy()释放资源。 - 通过
request()方法的配置对象设置方法、请求头、请求体、超时等参数。 - 根据响应状态码判断请求结果,200 表示成功。
- 设置
expectDataType可以自动解析响应数据。 - 需要配置
ohos.permission.INTERNET网络权限。 - 建议封装统一的请求工具类,实现代码复用。
网络请求是连接应用与云端的桥梁,掌握它之后,我们就可以构建真正具有云端能力的应用了。下一篇我们将深入讲解 HarmonyOS 状态管理机制。
更多推荐



所有评论(0)