鸿蒙网络请求从入门到精通:HttpURLConnection+第三方库,GET/POST/文件上传全覆盖
本文是鸿蒙NEXT开发实战系列第22篇,全面讲解鸿蒙网络请求开发。内容涵盖:权限配置、HttpURLConnection基础用法、GET/POST/PUT/DELETE请求实现、文件上传、axios第三方库使用、网络请求工具类封装、拦截器与错误处理等核心知识点。文章提供了完整的代码示例,包括请求并发控制、缓存策略和重试机制等性能优化方案,并针对不同项目规模给出了技术选型建议。通过本文,开发者可以掌
📖 鸿蒙NEXT开发实战系列 | 第22篇 | 网络篇 🎯 适合人群:有鸿蒙基础的开发者 ⏰ 阅读时间:约15分钟 | 💻 开发环境:DevEco Studio 5.0+
导航:上一篇:数据存储篇 | 系列目录 | 下一篇:WebSocket篇
网络请求是现代App的必备能力!无论是获取用户信息、提交表单数据,还是上传文件图片,都离不开网络请求。本文从鸿蒙原生 HttpURLConnection 讲起,再到 axios 等第三方库的使用,覆盖 GET 请求、POST 提交、文件上传、请求拦截、错误处理等全场景,附完整封装代码,助你一文掌握鸿蒙网络编程。
目录
一、权限配置:网络请求的第一步
在鸿蒙系统中,进行网络请求必须先声明网络权限。否则请求会直接失败。
1.1 声明网络权限
在 module.json5 文件中添加 INTERNET 权限:
{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "用于访问网络获取数据",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
]
}
}
注意:鸿蒙 NEXT 版本中,
INTERNET权限属于system_grant类型,无需用户手动授权,声明即可使用。
1.2 网络状态检测
建议在请求前检测网络状态:
import { connection } from '@kit.NetworkKit';
// 检测网络是否可用
async function checkNetwork(): Promise<boolean> {
try {
const netHandle = await connection.getDefaultNet();
const netCapabilities = await connection.getNetCapabilities(netHandle);
return netCapabilities?.bearerTypes?.length > 0;
} catch (err) {
console.error('网络检测失败', err);
return false;
}
}
二、HttpURLConnection 基础用法
http 模块是鸿蒙提供的原生网络请求 API,无需引入第三方库即可使用。
2.1 基础引入
import { http } from '@kit.NetworkKit';
2.2 创建请求对象
// 创建 httpRequest 实例
const httpRequest = http.createHttp();
// 请求配置
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
extraData: '', // POST 请求体
connectTimeout: 10000, // 连接超时 10 秒
readTimeout: 10000 // 读取超时 10 秒
};
三、GET 请求实战
GET 请求是最常见的请求方式,用于获取服务器数据。
3.1 基础 GET 请求
import { http } from '@kit.NetworkKit';
function doGetRequest() {
const httpRequest = http.createHttp();
httpRequest.request(
'https://api.example.com/users',
{
method: http.RequestMethod.GET,
header: {
'Content-Type': 'application/json'
},
connectTimeout: 10000,
readTimeout: 10000
},
(err, data) => {
if (!err) {
// 请求成功
console.info('状态码:', data.responseCode);
const result = JSON.parse(data.result as string);
console.info('返回数据:', JSON.stringify(result));
} else {
// 请求失败
console.error('请求失败:', err.message);
}
// 销毁请求对象,释放资源
httpRequest.destroy();
}
);
}
3.2 Promise 方式的 GET 请求
async function doGetWithPromise(): Promise<any> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(
'https://api.example.com/users',
{
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' }
}
);
if (response.responseCode === 200) {
const result = JSON.parse(response.result as string);
console.info('请求成功:', result);
return result;
} else {
throw new Error(`请求失败,状态码: ${response.responseCode}`);
}
} catch (err) {
console.error('请求异常:', err);
throw err;
} finally {
httpRequest.destroy();
}
}
3.3 GET 请求带查询参数
function buildQueryString(params: Record<string, string>): string {
return Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&');
}
async function doGetWithParams(params: Record<string, string>) {
const httpRequest = http.createHttp();
const queryString = buildQueryString(params);
const url = `https://api.example.com/users?${queryString}`;
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.GET
});
return JSON.parse(response.result as string);
} finally {
httpRequest.destroy();
}
}
// 使用示例
doGetWithParams({ page: '1', pageSize: '10', keyword: '鸿蒙' });
四、POST 请求实战
POST 请求用于向服务器提交数据,常见于登录、注册、表单提交等场景。
4.1 JSON 格式 POST 请求
async function doPostJson(url: string, data: object): Promise<any> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: JSON.stringify(data),
connectTimeout: 10000,
readTimeout: 10000
});
if (response.responseCode === 200 || response.responseCode === 201) {
return JSON.parse(response.result as string);
} else {
throw new Error(`请求失败,状态码: ${response.responseCode}`);
}
} finally {
httpRequest.destroy();
}
}
// 使用示例:用户登录
async function login(username: string, password: string) {
const result = await doPostJson('https://api.example.com/login', {
username,
password
});
console.info('登录结果:', result);
}
4.2 表单格式 POST 请求
async function doFormPost(url: string, formData: Record<string, string>) {
const httpRequest = http.createHttp();
const formBody = buildQueryString(formData);
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
extraData: formBody
});
return JSON.parse(response.result as string);
} finally {
httpRequest.destroy();
}
}
五、PUT 与 DELETE 请求
RESTful API 中常见的 PUT(更新)和 DELETE(删除)请求。
5.1 PUT 请求
async function doPut(url: string, data: object): Promise<any> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.PUT,
header: { 'Content-Type': 'application/json' },
extraData: JSON.stringify(data)
});
return JSON.parse(response.result as string);
} finally {
httpRequest.destroy();
}
}
// 使用示例:更新用户信息
doPut('https://api.example.com/users/1001', {
name: '张三',
age: 25
});
5.2 DELETE 请求
async function doDelete(url: string): Promise<any> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.DELETE,
header: { 'Content-Type': 'application/json' }
});
return response.responseCode === 200 ? JSON.parse(response.result as string) : null;
} finally {
httpRequest.destroy();
}
}
// 使用示例:删除用户
doDelete('https://api.example.com/users/1001');
六、文件上传实现
文件上传是实际开发中的高频需求,使用 multipart/form-data 格式实现。
6.1 基础文件上传
import { http } from '@kit.NetworkKit';
import { fileIo } from '@kit.CoreFileKit';
async function uploadFile(url: string, filePath: string, fileName: string): Promise<any> {
const httpRequest = http.createHttp();
try {
// 读取文件为 ArrayBuffer
const file = fileIo.openSync(filePath, fileIo.OpenMode.READ_ONLY);
const stat = fileIo.statSync(filePath);
const arrayBuffer = new ArrayBuffer(stat.size);
fileIo.readSync(file.fd, arrayBuffer);
fileIo.closeSync(file);
// 构建 multipart 请求
const boundary = '----HarmonyOSBoundary' + Date.now();
// 构建请求体
const headerPart =
`--${boundary}\r\n` +
`Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n` +
`Content-Type: application/octet-stream\r\n\r\n`;
const footerPart = `\r\n--${boundary}--\r\n`;
// 拼接完整请求体
const encoder = new util.TextEncoder();
const headerBuffer = encoder.encodeInto(headerPart);
const footerBuffer = encoder.encodeInto(footerPart);
const totalLength = headerBuffer.byteLength + arrayBuffer.byteLength + footerBuffer.byteLength;
const bodyBuffer = new Uint8Array(totalLength);
bodyBuffer.set(new Uint8Array(headerBuffer), 0);
bodyBuffer.set(new Uint8Array(arrayBuffer), headerBuffer.byteLength);
bodyBuffer.set(new Uint8Array(footerBuffer), headerBuffer.byteLength + arrayBuffer.byteLength);
const response = await httpRequest.request(url, {
method: http.RequestMethod.POST,
header: {
'Content-Type': `multipart/form-data; boundary=${boundary}`
},
extraData: bodyBuffer.buffer as ArrayBuffer
});
return JSON.parse(response.result as string);
} finally {
httpRequest.destroy();
}
}
// 使用示例
uploadFile(
'https://api.example.com/upload',
'/data/storage/el2/base/haps/entry/files/photo.jpg',
'photo.jpg'
);
提示:鸿蒙 NEXT 中更推荐使用
request模块的上传能力,系统会自动处理 multipart 格式。
6.2 使用系统 upload API
import { request } from '@kit.NetworkKit';
async function uploadWithSystemAPI(url: string, filePath: string) {
const uploadTask = await request.uploadFile(getContext(), {
url: url,
method: 'POST',
files: [{ filename: 'file', name: 'file', uri: filePath }],
data: [{ name: 'description', value: '用户上传图片' }]
});
uploadTask.on('complete', (taskState) => {
console.info('上传完成:', taskState);
});
uploadTask.on('fail', (taskState) => {
console.error('上传失败:', taskState);
});
}
七、使用 axios 第三方库
axios 是目前最流行的 HTTP 客户端库之一,鸿蒙社区也提供了适配版本。
7.1 安装 axios
ohpm install @ohos/axios
7.2 基础用法
import axios from '@ohos/axios';
// GET 请求
async function getUsers() {
const response = await axios.get('https://api.example.com/users');
console.info('用户列表:', response.data);
return response.data;
}
// POST 请求
async function createUser(userData: object) {
const response = await axios.post('https://api.example.com/users', userData);
console.info('创建成功:', response.data);
return response.data;
}
7.3 axios 配置项
import axios, { AxiosRequestConfig } from '@ohos/axios';
// 创建 axios 实例
const service = axios.create({
baseURL: 'https://api.example.com',
timeout: 15000,
headers: {
'Content-Type': 'application/json'
}
});
// 请求配置
const config: AxiosRequestConfig = {
method: 'post',
url: '/users',
data: { name: '张三', age: 25 }
};
service(config).then(response => {
console.info(response.data);
});
八、网络请求工具类封装
实际开发中,我们需要封装一个通用的网络请求工具类,统一管理请求配置和错误处理。
8.1 完整封装代码
// utils/HttpRequest.ets
import { http } from '@kit.NetworkKit';
// 响应数据结构
interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
}
// 请求配置
interface RequestConfig {
url: string;
method?: http.RequestMethod;
data?: object | string;
header?: Record<string, string>;
timeout?: number;
}
class HttpRequest {
private baseUrl: string = '';
private defaultHeader: Record<string, string> = {
'Content-Type': 'application/json'
};
private timeout: number = 15000;
// 设置基础配置
setBaseUrl(url: string): void {
this.baseUrl = url;
}
setToken(token: string): void {
this.defaultHeader['Authorization'] = `Bearer ${token}`;
}
// 核心请求方法
async request<T = any>(config: RequestConfig): Promise<ApiResponse<T>> {
const httpRequest = http.createHttp();
const fullUrl = this.baseUrl + config.url;
try {
const response = await httpRequest.request(fullUrl, {
method: config.method || http.RequestMethod.GET,
header: { ...this.defaultHeader, ...config.header },
extraData: typeof config.data === 'object' ?
JSON.stringify(config.data) : config.data,
connectTimeout: config.timeout || this.timeout,
readTimeout: config.timeout || this.timeout
});
const result: ApiResponse<T> = JSON.parse(response.result as string);
if (response.responseCode === 200) {
return result;
} else {
throw new Error(result.message || `请求失败: ${response.responseCode}`);
}
} catch (err) {
console.error('请求异常:', err);
throw err;
} finally {
httpRequest.destroy();
}
}
// GET 请求
async get<T = any>(url: string, params?: Record<string, string>): Promise<ApiResponse<T>> {
let fullUrl = url;
if (params) {
const queryString = Object.entries(params)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&');
fullUrl += `?${queryString}`;
}
return this.request<T>({ url: fullUrl, method: http.RequestMethod.GET });
}
// POST 请求
async post<T = any>(url: string, data?: object): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: http.RequestMethod.POST,
data
});
}
// PUT 请求
async put<T = any>(url: string, data?: object): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: http.RequestMethod.PUT,
data
});
}
// DELETE 请求
async delete<T = any>(url: string): Promise<ApiResponse<T>> {
return this.request<T>({
url,
method: http.RequestMethod.DELETE
});
}
}
// 导出单例
export const httpRequest = new HttpRequest();
8.2 使用示例
import { httpRequest } from '../utils/HttpRequest';
// 初始化配置
httpRequest.setBaseUrl('https://api.example.com');
httpRequest.setToken('your-token-here');
// 页面中使用
@Entry
@Component
struct UserListPage {
@State users: User[] = [];
async aboutToAppear() {
try {
// GET 请求获取用户列表
const result = await httpRequest.get<User[]>('/users', {
page: '1',
pageSize: '10'
});
this.users = result.data;
// POST 请求创建用户
await httpRequest.post('/users', {
name: '新用户',
age: 20
});
// PUT 请求更新用户
await httpRequest.put('/users/1001', {
name: '更新后的名字'
});
// DELETE 请求删除用户
await httpRequest.delete('/users/1001');
} catch (err) {
console.error('操作失败:', err);
}
}
build() {
List({ space: 10 }) {
ForEach(this.users, (user: User) => {
ListItem() {
Text(user.name)
.fontSize(16)
}
})
}
}
}
九、请求拦截器与错误处理
9.1 封装拦截器
// utils/HttpInterceptor.ets
import { http } from '@kit.NetworkKit';
type RequestInterceptor = (config: RequestConfig) => RequestConfig;
type ResponseInterceptor = (response: any) => any;
type ErrorInterceptor = (error: Error) => void;
class HttpInterceptor {
private requestInterceptors: RequestInterceptor[] = [];
private responseInterceptors: ResponseInterceptor[] = [];
private errorInterceptors: ErrorInterceptor[] = [];
// 添加请求拦截器
addRequestInterceptor(interceptor: RequestInterceptor): void {
this.requestInterceptors.push(interceptor);
}
// 添加响应拦截器
addResponseInterceptor(interceptor: ResponseInterceptor): void {
this.responseInterceptors.push(interceptor);
}
// 添加错误拦截器
addErrorInterceptor(interceptor: ErrorInterceptor): void {
this.errorInterceptors.push(interceptor);
}
// 执行请求拦截
applyRequestInterceptors(config: RequestConfig): RequestConfig {
let processedConfig = { ...config };
for (const interceptor of this.requestInterceptors) {
processedConfig = interceptor(processedConfig);
}
return processedConfig;
}
// 执行响应拦截
applyResponseInterceptors(response: any): any {
let processedResponse = response;
for (const interceptor of this.responseInterceptors) {
processedResponse = interceptor(processedResponse);
}
return processedResponse;
}
// 执行错误拦截
applyErrorInterceptors(error: Error): void {
for (const interceptor of this.errorInterceptors) {
interceptor(error);
}
}
}
export const httpInterceptor = new HttpInterceptor();
9.2 配置拦截器
import { httpInterceptor } from '../utils/HttpInterceptor';
import { router } from '@kit.ArkUI';
// 请求拦截器:自动添加 token
httpInterceptor.addRequestInterceptor((config) => {
const token = AppStorage.get<string>('userToken');
if (token) {
config.header = {
...config.header,
'Authorization': `Bearer ${token}`
};
}
console.info(`[请求] ${config.method} ${config.url}`);
return config;
});
// 响应拦截器:统一处理响应
httpInterceptor.addResponseInterceptor((response) => {
console.info(`[响应] 状态码: ${response.responseCode}`);
// 业务状态码处理
if (response.data?.code === 401) {
// Token 过期,跳转登录页
router.pushUrl({ url: 'pages/LoginPage' });
throw new Error('登录已过期,请重新登录');
}
return response;
});
// 错误拦截器:统一错误处理
httpInterceptor.addErrorInterceptor((error) => {
console.error('[错误]', error.message);
// 网络错误提示
if (error.message.includes('timeout')) {
promptAction.showToast({ message: '网络超时,请稍后重试' });
} else if (error.message.includes('Network')) {
promptAction.showToast({ message: '网络连接失败,请检查网络' });
}
});
9.3 错误码处理
function handleHttpError(statusCode: number): string {
const errorMap: Record<number, string> = {
400: '请求参数错误',
401: '未授权,请登录',
403: '拒绝访问',
404: '请求资源不存在',
408: '请求超时',
500: '服务器内部错误',
502: '网关错误',
503: '服务不可用',
504: '网关超时'
};
return errorMap[statusCode] || `未知错误: ${statusCode}`;
}
十、最佳实践与性能优化
10.1 请求并发控制
// 限制并发请求数量
async function batchRequest(urls: string[], maxConcurrent: number = 5) {
const results = [];
for (let i = 0; i < urls.length; i += maxConcurrent) {
const batch = urls.slice(i, i + maxConcurrent);
const batchResults = await Promise.all(
batch.map(url => httpRequest.get(url))
);
results.push(...batchResults);
}
return results;
}
10.2 请求缓存策略
const cacheMap = new Map<string, { data: any; timestamp: number }>();
const CACHE_DURATION = 5 * 60 * 1000; // 5 分钟缓存
async function getWithCache<T>(url: string): Promise<T> {
const cached = cacheMap.get(url);
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
return cached.data;
}
const result = await httpRequest.get<T>(url);
cacheMap.set(url, { data: result.data, timestamp: Date.now() });
return result.data;
}
10.3 请求重试机制
async function requestWithRetry(
requestFn: () => Promise<any>,
maxRetries: number = 3,
delay: number = 1000
): Promise<any> {
for (let i = 0; i < maxRetries; i++) {
try {
return await requestFn();
} catch (err) {
if (i === maxRetries - 1) throw err;
console.warn(`请求失败,${delay}ms 后重试 (${i + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
总结
本文从基础到进阶,完整介绍了鸿蒙网络请求的各个方面:
|
内容 |
说明 |
|---|---|
|
权限配置 |
|
|
HttpURLConnection |
原生 API,无需额外依赖 |
|
GET/POST/PUT/DELETE |
覆盖 RESTful 全部请求方式 |
|
文件上传 |
支持 multipart 和系统 upload API |
|
axios 第三方库 |
更简洁的 API,支持拦截器 |
|
工具类封装 |
统一管理请求配置和错误处理 |
|
拦截器 |
请求/响应拦截,统一添加 token |
|
性能优化 |
并发控制、缓存策略、重试机制 |
选择建议:
-
简单项目:直接使用
http模块 -
复杂项目:封装工具类 + 拦截器
-
团队协作:使用 axios 等成熟库
掌握这些知识,你就能应对鸿蒙开发中 99% 的网络请求场景了!
📚 系列文章推荐
标签:鸿蒙网络请求 HTTP axios 网络编程 HarmonyOS HttpURLConnection 文件上传 请求封装
💡 下期预告:WebSocket 实时通信实战,实现聊天室功能!
更多推荐


所有评论(0)