第九章:网络请求
本章配套代码:
code/Chapter9(HTTP GET 请求 Demo) 前置要求:已完成数据持久化章节
9.1 学习目标
- 掌握
http模块发送 GET/POST 请求 - 掌握 JSON 数据解析
- 理解超时、错误处理与重试
- 学会封装请求工具类
9.2 网络权限
发起网络请求前,必须在 module.json5 声明 INTERNET 权限:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
⚠️ 忘记加权限是最常见的网络请求报错原因(报错
201无权限)。
9.3 HTTP GET 请求
import { http } from '@kit.NetworkKit'
async function fetchData(): Promise<string> {
const httpRequest = http.createHttp() // ① 创建请求对象
try {
const response = await httpRequest.request( // ② 发起请求
'https://v1.jinrishici.com/all.json',
{
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json'
},
expectDataType: http.HttpDataType.STRING,
connectTimeout: 10000, // 连接超时(ms)
readTimeout: 10000 // 读取超时(ms)
}
)
if (response.responseCode === 200) { // ③ 检查状态码
return response.result as string
}
throw new Error(`HTTP Error: ${response.responseCode}`)
} finally {
httpRequest.destroy() // ④ 必须销毁,释放资源
}
}
请求流程:
createHttp() → request() → 检查 responseCode → 解析 result → destroy()
① ② ③ ④ ⑤
🔑
destroy()必须调用(finally 中),否则连接泄漏。
💡 这里使用公开接口「今日诗词」:每次 GET 都会返回一句随机古诗词(字段
content诗句、origin出处、author作者、category分类),把网络请求和诗词主题结合起来,文艺又实用。
9.4 POST 请求
async function postData(data: object): Promise<boolean> {
const httpRequest = http.createHttp()
try {
const response = await httpRequest.request(
'https://api.example.com/data',
{
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: JSON.stringify(data) // 请求体(JSON 字符串)
}
)
return response.responseCode === 200 || response.responseCode === 201
} finally {
httpRequest.destroy()
}
}
💡 POST 没有合适的公开诗词示例接口,
api.example.com为示意地址,实际开发时替换为后端接口即可。
其他方法:
// PUT(更新)
method: http.RequestMethod.PUT
// DELETE(删除)
method: http.RequestMethod.DELETE
// 请求头
header: { 'Content-Type': 'application/json', 'Authorization': 'Bearer xxx' }
9.5 数据解析
9.5.1 JSON 解析
// 定义用户数据类型与响应模型
interface User {
id: number
name: string
email: string
}
interface ApiResponse<T> {
code: number
message: string
data: T
}
// 解析
const result = JSON.parse(response.result as string) as ApiResponse<User[]>
if (result.code === 0) {
console.log(result.data) // 泛型推导出类型安全的数据
}
💡 用泛型接口 +
as断言,让 JSON 数据获得类型安全。
9.5.2 封装请求工具类
import { http } from '@kit.NetworkKit'
interface ApiResponse<T> {
code: number
message: string
data: T
}
class HttpUtil {
private static instance: HttpUtil
private baseUrl: string = 'https://api.example.com'
static getInstance(): HttpUtil {
if (!HttpUtil.instance) {
HttpUtil.instance = new HttpUtil()
}
return HttpUtil.instance
}
async get<T>(path: string): Promise<T> {
const httpRequest = http.createHttp()
try {
const response = await httpRequest.request(
`${this.baseUrl}${path}`,
{
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' }
}
)
const result = JSON.parse(response.result as string) as ApiResponse<T>
if (result.code === 0) {
return result.data
}
throw new Error(result.message)
} finally {
httpRequest.destroy()
}
}
async post<T>(path: string, data: object): Promise<T> {
const httpRequest = http.createHttp()
try {
const response = await httpRequest.request(
`${this.baseUrl}${path}`,
{
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify(data)
}
)
const result = JSON.parse(response.result as string) as ApiResponse<T>
if (result.code === 0) {
return result.data
}
throw new Error(result.message)
} finally {
httpRequest.destroy()
}
}
}
export default HttpUtil
9.6 页面中的使用(Loading/Error 三态)
网络请求页面应处理 加载中 / 失败 / 成功 三种状态:
@Entry
@ComponentV2
struct UserListPage {
@Local users: User[] = []
@Local isLoading: boolean = false
@Local error: string = ''
async aboutToAppear(): Promise<void> {
await this.loadUsers()
}
async loadUsers() {
this.isLoading = true
this.error = ''
try {
this.users = await HttpUtil.getInstance().get<User[]>('/users')
} catch (e) {
this.error = (e as Error).message
} finally {
this.isLoading = false
}
}
build() {
Column({ space: 16 }) {
Text('用户列表').fontSize(24)
if (this.isLoading) {
LoadingProgress().width(40).height(40) // 加载中
} else if (this.error) {
Column() {
Text(this.error).fontColor(Color.Red) // 失败
Button('重试').onClick(() => this.loadUsers())
}
} else {
List({ space: 8 }) { // 成功
ForEach(this.users, (user: User) => {
ListItem() { /* 用户卡片 */ }
})
}
}
}
.padding(16)
}
}
三态处理范式:
isLoading ? LoadingProgress
: error ? (错误提示 + 重试按钮)
: (数据列表)
9.7 错误处理与重试
9.7.1 超时与网络异常
try {
const response = await httpRequest.request(url, {
connectTimeout: 10000, // 连接超时
readTimeout: 10000 // 读取超时
})
} catch (e) {
// 网络不可达、超时、解析失败等
console.error((e as BusinessError).message)
}
9.7.2 自动重试
async function requestWithRetry<T>(path: string): Promise<T> {
let retryCount = 0
const maxRetries = 3
while (retryCount < maxRetries) {
try {
return await HttpUtil.getInstance().get<T>(path)
} catch (error) {
retryCount++
if (retryCount >= maxRetries) {
throw error
}
await new Promise(resolve => setTimeout(resolve, 1000 * retryCount)) // 递增退避
}
}
throw new Error('Max retries exceeded')
}
9.8 综合示例
对应 code/Chapter9 的 Index.ets,使用公开 API「今日诗词」演示真实请求,每次请求随机返回一句古 诗词:
import { http } from '@kit.NetworkKit'
// 今日诗词接口返回的数据结构
interface PoemResult {
content: string // 诗句
origin: string // 出处(诗名/词牌名)
author: string // 作者
category: string // 分类
}
@Entry
@ComponentV2
struct Index {
@Local responseData: string = '点击按钮,随机收获一句古诗词'
@Local isLoading: boolean = false
@Local statusMessage: string = ''
async fetchData() {
this.isLoading = true
this.statusMessage = '请求中...'
const httpRequest = http.createHttp()
try {
const response = await httpRequest.request(
'https://v1.jinrishici.com/all.json',
{
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' },
expectDataType: http.HttpDataType.STRING,
connectTimeout: 10000,
readTimeout: 10000
}
)
if (response.responseCode === 200) {
const poem = JSON.parse(response.result as string) as PoemResult
this.responseData = `「${poem.content}」\n—— ${poem.author}《${poem.origin}》\n分类:${poem.category}`
this.statusMessage = `请求成功 (${response.responseCode})`
} else {
this.statusMessage = `请求失败 (${response.responseCode})`
}
} catch (e) {
this.statusMessage = `异常: ${(e as Error).message}`
} finally {
httpRequest.destroy()
this.isLoading = false
}
}
build() {
// 按钮 + 状态 + LoadingProgress + 响应展示(白色卡片)
}
}
运行效果:
- 点击 "GET 请求" 发起真实网络请求
- 加载中显示 LoadingProgress,状态文字提示"请求中..."
- 成功后状态变绿,展示一句随机古诗词(含诗句、作者、出处、分类)
- 失败时状态显示错误码/异常信息
运行效果截图:



🔧 提示:模拟器可访问外网。若失败请检查:INTERNET 权限、网络连接、今日诗词 API 可达性。
9.9 常见问题
Q:请求报错 201?
没有 INTERNET 权限。检查 module.json5 的 requestPermissions。
Q:如何设置超时?
request() 的 options 中设 connectTimeout、readTimeout。
Q:如何实现文件上传?
POST + extraData 传文件流,或使用 @ohos.request 上传任务。
Q:response.result 如何解析?
根据 expectDataType 转换。字符串 JSON 用 JSON.parse。
9.10 本章小结
| 知识点 | 说明 |
|---|---|
| INTERNET 权限 | 必备前置条件 |
| GET/POST | http.createHttp() + request() |
| JSON 解析 | 泛型 + as 断言 |
| 三态处理 | 加载中/失败/成功 |
| 超时与重试 | connectTimeout + 退避重试 |
| 工具类封装 | 单例 + 泛型 |