网络请求
HarmonyOS 使用 @kit.NetworkKit 进行网络请求,支持 HTTP/HTTPS、WebSocket、文件上传下载以及网络状态监听。
前置配置
在 module.json5 中声明网络权限:
json5
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:reason_internet",
"usedScene": {}
}
]
}
}提示
INTERNET 权限无需动态申请,声明后即可使用。
HTTP 请求
API 列表
| API | 说明 | 起始版本 |
|---|---|---|
http.createHttp() | 创建 HTTP 请求实例 | API 6 |
HttpRequest.request() | 发起网络请求 | API 6 |
HttpRequest.destroy() | 销毁请求实例,释放资源 | API 6 |
HttpRequest.on('headersReceive') | 监听响应头接收事件 | API 6 |
HttpRequest.off('headersReceive') | 取消监听响应头接收事件 | API 6 |
RequestMethod 枚举
| 枚举值 | 说明 |
|---|---|
GET | GET 请求 |
POST | POST 请求 |
PUT | PUT 请求 |
DELETE | DELETE 请求 |
HEAD | HEAD 请求 |
OPTIONS | OPTIONS 请求 |
TRACE | TRACE 请求 |
CONNECT | CONNECT 请求 |
HttpDataType 枚举
| 枚举值 | 说明 |
|---|---|
STRING | 返回字符串 |
OBJECT | 返回 JSON 对象 |
ARRAY_BUFFER | 返回 ArrayBuffer |
GET 请求
typescript
import { http } from '@kit.NetworkKit'
async function fetchUser(userId: number): Promise<void> {
const request = http.createHttp()
try {
const response = await request.request(`https://api.example.com/users/${userId}`, {
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer your-token'
},
expectDataType: http.HttpDataType.STRING,
connectTimeout: 10000,
readTimeout: 10000
})
if (response.responseCode === 200) {
const data = JSON.parse(response.result as string)
console.info('用户信息:', JSON.stringify(data))
} else {
console.error('请求失败:', response.responseCode)
}
} catch (error) {
console.error('网络错误:', JSON.stringify(error))
} finally {
request.destroy() // 必须销毁,避免内存泄漏
}
}POST 请求(JSON)
typescript
import { http } from '@kit.NetworkKit'
interface CreateUserRequest {
name: string
email: string
age: number
}
async function createUser(user: CreateUserRequest): Promise<void> {
const request = http.createHttp()
try {
const response = await request.request('https://api.example.com/users', {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: JSON.stringify(user),
expectDataType: http.HttpDataType.STRING
})
if (response.responseCode === 201) {
const result = JSON.parse(response.result as string)
console.info('创建成功:', JSON.stringify(result))
}
} catch (error) {
console.error('创建失败:', JSON.stringify(error))
} finally {
request.destroy()
}
}表单请求
typescript
async function uploadForm(): Promise<void> {
const request = http.createHttp()
const formData = 'name=张三&age=25'
try {
const response = await request.request('https://api.example.com/form', {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
extraData: formData,
expectDataType: http.HttpDataType.STRING
})
console.info('响应:', response.result)
} finally {
request.destroy()
}
}监听响应头
typescript
import { http } from '@kit.NetworkKit'
async function requestWithHeaderListener(): Promise<void> {
const request = http.createHttp()
// 监听响应头
request.on('headersReceive', (header) => {
console.info('响应头:', JSON.stringify(header))
})
try {
const response = await request.request('https://api.example.com/data', {
method: http.RequestMethod.GET
})
console.info('响应体:', response.result)
} finally {
request.off('headersReceive')
request.destroy()
}
}文件上传
使用 HTTP 上传
typescript
import { http } from '@kit.NetworkKit'
async function uploadFile(filePath: string): Promise<void> {
const request = http.createHttp()
try {
const response = await request.request('https://api.example.com/upload', {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'multipart/form-data'
},
// 使用文件路径上传
extraData: {
"file": filePath,
"name": "avatar.jpg"
},
expectDataType: http.HttpDataType.STRING
})
console.info('上传结果:', response.result)
} finally {
request.destroy()
}
}上传进度监听
typescript
import { http } from '@kit.NetworkKit'
async function uploadWithProgress(filePath: string): Promise<void> {
const request = http.createHttp()
try {
// 监听上传进度
request.on('dataReceiveProgress', (receiveData) => {
console.info('上传进度:', receiveData.receiveSize, '/', receiveData.totalSize)
})
const response = await request.request('https://api.example.com/upload', {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'multipart/form-data'
},
extraData: {
"file": filePath,
"name": "avatar.jpg"
},
expectDataType: http.HttpDataType.STRING
})
console.info('上传完成:', response.result)
} finally {
request.off('dataReceiveProgress')
request.destroy()
}
}文件下载
使用 request 下载
typescript
import { http } from '@kit.NetworkKit'
import { fileIo } from '@kit.CoreFileKit'
async function downloadFile(url: string, savePath: string): Promise<void> {
const request = http.createHttp()
try {
const response = await request.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER
})
if (response.responseCode === 200) {
const file = fileIo.openSync(savePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY)
fileIo.writeSync(file.fd, response.result as ArrayBuffer)
fileIo.closeSync(file)
console.info('下载完成:', savePath)
}
} catch (error) {
console.error('下载失败:', JSON.stringify(error))
} finally {
request.destroy()
}
}下载进度监听
typescript
import { http } from '@kit.NetworkKit'
import { fileIo } from '@kit.CoreFileKit'
async function downloadWithProgress(url: string, savePath: string): Promise<void> {
const request = http.createHttp()
try {
// 监听下载进度
request.on('dataReceiveProgress', (receiveData) => {
const progress = (receiveData.receiveSize / receiveData.totalSize) * 100
console.info(`下载进度: ${progress.toFixed(2)}%`)
})
const response = await request.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.ARRAY_BUFFER
})
if (response.responseCode === 200) {
const file = fileIo.openSync(savePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY)
fileIo.writeSync(file.fd, response.result as ArrayBuffer)
fileIo.closeSync(file)
console.info('下载完成:', savePath)
}
} catch (error) {
console.error('下载失败:', JSON.stringify(error))
} finally {
request.off('dataReceiveProgress')
request.destroy()
}
}请求封装
建议封装统一的请求工具:
typescript
// utils/HttpUtil.ets
import { http } from '@kit.NetworkKit'
interface RequestOptions {
method?: http.RequestMethod
header?: Record<string, string>
body?: object | string
timeout?: number
}
class HttpUtil {
private baseURL: string = 'https://api.example.com'
private token: string = ''
setToken(token: string) {
this.token = token
}
async request<T>(url: string, options: RequestOptions = {}): Promise<T> {
const request = http.createHttp()
const fullURL = url.startsWith('http') ? url : `${this.baseURL}${url}`
try {
const header: Record<string, string> = {
'Content-Type': 'application/json',
...options.header
}
if (this.token) {
header['Authorization'] = `Bearer ${this.token}`
}
const response = await request.request(fullURL, {
method: options.method || http.RequestMethod.GET,
header,
extraData: typeof options.body === 'string' ? options.body : JSON.stringify(options.body),
expectDataType: http.HttpDataType.STRING,
connectTimeout: options.timeout || 10000,
readTimeout: options.timeout || 10000
})
if (response.responseCode >= 200 && response.responseCode < 300) {
return JSON.parse(response.result as string) as T
} else {
throw new Error(`HTTP ${response.responseCode}: ${response.result}`)
}
} finally {
request.destroy()
}
}
get<T>(url: string, header?: Record<string, string>): Promise<T> {
return this.request<T>(url, { method: http.RequestMethod.GET, header })
}
post<T>(url: string, body?: object, header?: Record<string, string>): Promise<T> {
return this.request<T>(url, { method: http.RequestMethod.POST, body, header })
}
put<T>(url: string, body?: object, header?: Record<string, string>): Promise<T> {
return this.request<T>(url, { method: http.RequestMethod.PUT, body, header })
}
delete<T>(url: string, header?: Record<string, string>): Promise<T> {
return this.request<T>(url, { method: http.RequestMethod.DELETE, header })
}
}
export const httpUtil = new HttpUtil()使用示例:
typescript
import { httpUtil } from '../utils/HttpUtil'
interface User {
id: number
name: string
email: string
}
// GET 请求
const user = await httpUtil.get<User>('/users/1')
// POST 请求
const newUser = await httpUtil.post<User>('/users', {
name: '张三',
email: 'zhangsan@example.com'
})WebSocket
API 列表
| API | 说明 | 起始版本 |
|---|---|---|
webSocket.createWebSocket() | 创建 WebSocket 实例 | API 7 |
WebSocket.connect() | 连接 WebSocket 服务器 | API 7 |
WebSocket.send() | 发送消息 | API 7 |
WebSocket.close() | 关闭连接 | API 7 |
WebSocket.on('open') | 监听连接打开事件 | API 7 |
WebSocket.on('message') | 监听消息接收事件 | API 7 |
WebSocket.on('close') | 监听连接关闭事件 | API 7 |
WebSocket.on('error') | 监听错误事件 | API 7 |
基础用法
typescript
import { webSocket } from '@kit.NetworkKit'
class WebSocketClient {
private ws: webSocket.WebSocket | null = null
connect(url: string) {
this.ws = webSocket.createWebSocket()
this.ws.on('open', () => {
console.info('WebSocket 连接成功')
})
this.ws.on('message', (err, data) => {
console.info('收到消息:', data)
})
this.ws.on('close', () => {
console.info('WebSocket 连接关闭')
})
this.ws.on('error', (err) => {
console.error('WebSocket 错误:', JSON.stringify(err))
})
this.ws.connect(url)
}
send(message: string) {
if (this.ws) {
this.ws.send(message)
}
}
close() {
if (this.ws) {
this.ws.close()
this.ws = null
}
}
}完整封装示例
typescript
import { webSocket } from '@kit.NetworkKit'
interface WebSocketOptions {
url: string
reconnect?: boolean
reconnectInterval?: number
maxReconnectAttempts?: number
}
class WebSocketManager {
private ws: webSocket.WebSocket | null = null
private options: WebSocketOptions
private reconnectAttempts: number = 0
private reconnectTimer: number | null = null
private messageHandlers: Array<(data: string) => void> = []
constructor(options: WebSocketOptions) {
this.options = {
reconnect: true,
reconnectInterval: 3000,
maxReconnectAttempts: 5,
...options
}
}
connect(): void {
this.ws = webSocket.createWebSocket()
this.ws.on('open', () => {
console.info('WebSocket 连接成功')
this.reconnectAttempts = 0
})
this.ws.on('message', (err, data) => {
if (err) {
console.error('消息接收错误:', JSON.stringify(err))
return
}
this.messageHandlers.forEach(handler => handler(data as string))
})
this.ws.on('close', () => {
console.info('WebSocket 连接关闭')
this.ws = null
if (this.options.reconnect) {
this.attemptReconnect()
}
})
this.ws.on('error', (err) => {
console.error('WebSocket 错误:', JSON.stringify(err))
})
this.ws.connect(this.options.url)
}
private attemptReconnect(): void {
if (this.reconnectAttempts >= (this.options.maxReconnectAttempts || 5)) {
console.error('重连次数已达上限')
return
}
this.reconnectAttempts++
console.info(`第 ${this.reconnectAttempts} 次重连...`)
this.reconnectTimer = setTimeout(() => {
this.connect()
}, this.options.reconnectInterval)
}
send(message: string): void {
if (this.ws) {
this.ws.send(message)
} else {
console.warn('WebSocket 未连接')
}
}
onMessage(handler: (data: string) => void): void {
this.messageHandlers.push(handler)
}
offMessage(handler: (data: string) => void): void {
const index = this.messageHandlers.indexOf(handler)
if (index > -1) {
this.messageHandlers.splice(index, 1)
}
}
close(): void {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer)
this.reconnectTimer = null
}
if (this.ws) {
this.ws.close()
this.ws = null
}
}
}
// 使用示例
const wsManager = new WebSocketManager({
url: 'wss://api.example.com/ws',
reconnect: true,
reconnectInterval: 3000,
maxReconnectAttempts: 5
})
wsManager.onMessage((data) => {
console.info('收到消息:', data)
})
wsManager.connect()
wsManager.send(JSON.stringify({ type: 'hello', data: 'world' }))网络状态监听
API 列表
| API | 说明 | 起始版本 |
|---|---|---|
connection.getDefaultNetSync() | 获取默认网络 | API 9 |
connection.getNetCapabilities() | 获取网络能力信息 | API 9 |
connection.getConnectionProperties() | 获取网络连接属性 | API 9 |
connection.on('netAvailable') | 监听网络可用事件 | API 9 |
connection.on('netUnavailable') | 监听网络不可用事件 | API 9 |
connection.on('netCapabilitiesChange') | 监听网络能力变化事件 | API 9 |
connection.off('netAvailable') | 取消监听网络可用事件 | API 9 |
获取当前网络信息
typescript
import { connection } from '@kit.NetworkKit'
function getNetworkInfo(): void {
try {
const netHandle = connection.getDefaultNetSync()
if (netHandle.netId === 0) {
console.info('当前无网络连接')
return
}
const capabilities = connection.getNetCapabilitiesSync(netHandle)
console.info('网络类型:', capabilities.bearerTypes)
console.info('网络能力:', capabilities.networkCap)
const properties = connection.getConnectionPropertiesSync(netHandle)
console.info('链路信息:', properties.linkAddress)
} catch (error) {
console.error('获取网络信息失败:', JSON.stringify(error))
}
}监听网络状态变化
typescript
import { connection } from '@kit.NetworkKit'
class NetworkMonitor {
private netAvailableHandler: ((data: connection.NetHandle) => void) | null = null
private netUnavailableHandler: (() => void) | null = null
private netCapabilitiesChangeHandler: ((data: connection.NetCapabilityInfo) => void) | null = null
startMonitoring(): void {
// 监听网络可用
this.netAvailableHandler = (data) => {
console.info('网络可用, netId:', data.netId)
}
connection.on('netAvailable', this.netAvailableHandler)
// 监听网络不可用
this.netUnavailableHandler = () => {
console.info('网络不可用')
}
connection.on('netUnavailable', this.netUnavailableHandler)
// 监听网络能力变化
this.netCapabilitiesChangeHandler = (data) => {
console.info('网络能力变化:', JSON.stringify(data))
}
connection.on('netCapabilitiesChange', this.netCapabilitiesChangeHandler)
}
stopMonitoring(): void {
if (this.netAvailableHandler) {
connection.off('netAvailable', this.netAvailableHandler)
}
if (this.netUnavailableHandler) {
connection.off('netUnavailable', this.netUnavailableHandler)
}
if (this.netCapabilitiesChangeHandler) {
connection.off('netCapabilitiesChange', this.netCapabilitiesChangeHandler)
}
}
}
// 使用示例
const monitor = new NetworkMonitor()
monitor.startMonitoring()
// 页面销毁时调用
// monitor.stopMonitoring()判断网络类型
typescript
import { connection } from '@kit.NetworkKit'
enum NetworkType {
NONE = 'none',
WIFI = 'wifi',
CELLULAR = 'cellular',
ETHERNET = 'ethernet',
UNKNOWN = 'unknown'
}
function getNetworkType(): NetworkType {
try {
const netHandle = connection.getDefaultNetSync()
if (netHandle.netId === 0) {
return NetworkType.NONE
}
const capabilities = connection.getNetCapabilitiesSync(netHandle)
const bearerTypes = capabilities.bearerTypes
if (bearerTypes.includes(connection.NetBearType.BEARER_WIFI)) {
return NetworkType.WIFI
}
if (bearerTypes.includes(connection.NetBearType.BEARER_CELLULAR)) {
return NetworkType.CELLULAR
}
if (bearerTypes.includes(connection.NetBearType.BEARER_ETHERNET)) {
return NetworkType.ETHERNET
}
return NetworkType.UNKNOWN
} catch {
return NetworkType.NONE
}
}
// 使用示例
const networkType = getNetworkType()
console.info('当前网络类型:', networkType)错误处理
常见错误码
| 错误码 | 说明 | 处理建议 |
|---|---|---|
| 401 | 解析参数错误 | 检查请求参数格式 |
| 404 | 找不到文件 | 检查文件路径 |
| 500 | 未知错误 | 查看系统日志 |
| 2300001 | 网络不可用 | 检查网络连接 |
| 2300002 | 网络请求超时 | 增加超时时间或检查网络 |
| 2300003 | 网络请求失败 | 检查 URL 和网络状态 |
| 2300028 | 网络请求被取消 | 用户主动取消 |
错误处理示例
typescript
import { http } from '@kit.NetworkKit'
interface NetworkError {
code: number
message: string
}
async function safeRequest<T>(
url: string,
options?: http.HttpRequestOptions
): Promise<T | null> {
const request = http.createHttp()
try {
const response = await request.request(url, {
connectTimeout: 10000,
readTimeout: 10000,
...options
})
if (response.responseCode >= 200 && response.responseCode < 300) {
return JSON.parse(response.result as string) as T
} else {
console.error(`HTTP 错误: ${response.responseCode}`)
return null
}
} catch (error) {
const err = error as NetworkError
console.error('请求失败:', err.code, err.message)
// 根据错误码处理
switch (err.code) {
case 2300001:
// 网络不可用,提示用户检查网络
break
case 2300002:
// 超时,可以重试
break
default:
// 其他错误
break
}
return null
} finally {
request.destroy()
}
}最佳实践
- 始终销毁请求对象:使用完
http.createHttp()后必须调用destroy() - 设置超时时间:避免请求挂起,建议设置 10-30 秒
- 统一封装:建议封装请求工具类,统一处理错误和 token
- 类型安全:为请求和响应定义接口
- 错误处理:使用 try/catch 捕获网络异常,根据错误码分类处理
- WebSocket 重连:生产环境建议实现自动重连机制
- 网络状态监听:在需要时监听网络变化,及时提示用户
- 取消请求:页面销毁时取消未完成的请求,避免内存泄漏