鸿蒙网络请求从入门到精通:HttpURLConnection+第三方库,GET/POST/文件上传全覆盖
鸿蒙NEXT开发实战系列| 第22篇 | 网络篇 适合人群有鸿蒙基础的开发者 ⏰阅读时间约15分钟 | 开发环境DevEco Studio 5.0导航上一篇数据存储篇 | 系列目录 | 下一篇WebSocket篇网络请求是现代App的必备能力无论是获取用户信息、提交表单数据还是上传文件图片都离不开网络请求。本文从鸿蒙原生 HttpURLConnection 讲起再到 axios 等第三方库的使用覆盖 GET 请求、POST 提交、文件上传、请求拦截、错误处理等全场景附完整封装代码助你一文掌握鸿蒙网络编程。目录一、权限配置网络请求的第一步二、HttpURLConnection 基础用法三、GET 请求实战四、POST 请求实战五、PUT 与 DELETE 请求六、文件上传实现七、使用 axios 第三方库八、网络请求工具类封装九、请求拦截器与错误处理十、最佳实践与性能优化总结一、权限配置网络请求的第一步在鸿蒙系统中进行网络请求必须先声明网络权限。否则请求会直接失败。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(): Promiseboolean { 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(): Promiseany { 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: Recordstring, string): string { return Object.entries(params) .map(([key, value]) ${encodeURIComponent(key)}${encodeURIComponent(value)}) .join(); } async function doGetWithParams(params: Recordstring, 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): Promiseany { 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: Recordstring, 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): Promiseany { 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): Promiseany { 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): Promiseany { 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; namefile; 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 APIimport { 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 安装 axiosohpm install ohos/axios7.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 ApiResponseT any { code: number; message: string; data: T; } // 请求配置 interface RequestConfig { url: string; method?: http.RequestMethod; data?: object | string; header?: Recordstring, string; timeout?: number; } class HttpRequest { private baseUrl: string ; private defaultHeader: Recordstring, 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 requestT any(config: RequestConfig): PromiseApiResponseT { 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: ApiResponseT 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 getT any(url: string, params?: Recordstring, string): PromiseApiResponseT { let fullUrl url; if (params) { const queryString Object.entries(params) .map(([key, value]) ${key}${encodeURIComponent(value)}) .join(); fullUrl ?${queryString}; } return this.requestT({ url: fullUrl, method: http.RequestMethod.GET }); } // POST 请求 async postT any(url: string, data?: object): PromiseApiResponseT { return this.requestT({ url, method: http.RequestMethod.POST, data }); } // PUT 请求 async putT any(url: string, data?: object): PromiseApiResponseT { return this.requestT({ url, method: http.RequestMethod.PUT, data }); } // DELETE 请求 async deleteT any(url: string): PromiseApiResponseT { return this.requestT({ 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.getUser[](/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.getstring(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: Recordnumber, 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 Mapstring, { data: any; timestamp: number }(); const CACHE_DURATION 5 * 60 * 1000; // 5 分钟缓存 async function getWithCacheT(url: string): PromiseT { const cached cacheMap.get(url); if (cached Date.now() - cached.timestamp CACHE_DURATION) { return cached.data; } const result await httpRequest.getT(url); cacheMap.set(url, { data: result.data, timestamp: Date.now() }); return result.data; }10.3 请求重试机制async function requestWithRetry( requestFn: () Promiseany, maxRetries: number 3, delay: number 1000 ): Promiseany { 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)); } } }总结本文从基础到进阶完整介绍了鸿蒙网络请求的各个方面内容说明权限配置ohos.permission.INTERNET必须声明HttpURLConnection原生 API无需额外依赖GET/POST/PUT/DELETE覆盖 RESTful 全部请求方式文件上传支持 multipart 和系统 upload APIaxios 第三方库更简洁的 API支持拦截器工具类封装统一管理请求配置和错误处理拦截器请求/响应拦截统一添加 token性能优化并发控制、缓存策略、重试机制选择建议简单项目直接使用http模块复杂项目封装工具类 拦截器团队协作使用 axios 等成熟库掌握这些知识你就能应对鸿蒙开发中 99% 的网络请求场景了系列文章推荐第21篇数据持久化之首选项与关系型数据库第23篇WebSocket 实时通信实战第24篇网络状态监听与弱网优化第25篇网络请求缓存策略详解标签鸿蒙网络请求HTTPaxios网络编程HarmonyOSHttpURLConnection文件上传请求封装下期预告WebSocket 实时通信实战实现聊天室功能