ToB企服应用市场:ToB评测及商务社交产业平台

标题: 基于@ohos/axios学习HarmonyOS Next的网络数据哀求 [打印本页]

作者: 九天猎人    时间: 2025-1-3 00:13
标题: 基于@ohos/axios学习HarmonyOS Next的网络数据哀求
基于@ohos/axios学习HarmonyOS Next的网络数据哀求

     前言

     在 HarmonyOS Next 应用开发中,网络哀求是一个非常重要的功能。本文将通过分析 @ohos/axios 的实现,深入相识 HarmonyOS Next 的网络数据哀求机制。
     一、基础知识

     1.1 @ohos/axios 简介

     @ohos/axios 是 Axios 在 HarmonyOS 平台的适配版本。Axios 是一个基于 Promise 的 HTTP 客户端,可以在浏览器和 Node.js 环境中利用。@ohos/axios 保留了 Axios 的主要特性,同时适配了 HarmonyOS 的网络 API。
     1.2 安装与配置

                                   登录后复制                        
  1. ohpm install @ohos/axios
复制代码
      
                       在下令行中利用 ohpm install @ohos/axios 下令安装 @ohos/axios 模块。
     需要在 module.json5 中配置权限:
                                   登录后复制                        
  1. {
  2.   "module": {
  3.     "requestPermissions": [
  4.       {
  5.         "name": "ohos.permission.INTERNET"
  6.       }
  7.     ]
  8.   }
  9. }
复制代码
      
                       剖析:
     
     二、基本利用

     2.1 创建实例

                                   登录后复制                        
  1. import axios from '@ohos/axios';
  2. // 创建实例
  3. const instance = axios.create({
  4.   baseURL: 'https://api.example.com',
  5.   timeout: 5000,
  6.   headers: {'X-Custom-Header': 'custom-value'}
  7. });
复制代码
      
                       剖析:
     
     2.2 基本哀求示例

                                   登录后复制                        
  1. // GET 请求
  2. async function getData() {
  3.   try {
  4.     const response = await axios.get('/user/123');
  5.     console.info('Response:', response.data);
  6.   } catch (error) {
  7.     console.error('Error:', error);
  8.   }
  9. }
  10. // POST 请求
  11. async function postData() {
  12.   try {
  13.     const response = await axios.post('/user', {
  14.       name: 'John',
  15.       age: 30
  16.     });
  17.     console.info('Response:', response.data);
  18.   } catch (error) {
  19.     console.error('Error:', error);
  20.   }
  21. }
复制代码
      
                       剖析:
     
     三、深入实现原理

     3.1 HTTP 哀求适配器

     3.1.1 基础 HTTP 哀求适配器

                                   登录后复制                        
  1. // library/src/main/ets/components/lib/adapters/ohos/http.js
  2. import http from '@ohos.net.http';
  3. export default function httpAdapter(config) {
  4.   return new Promise((resolve, reject) => {
  5.     let httpRequest = http.createHttp();
  6.    
  7.     // 构建请求配置
  8.     const requestConfig = {
  9.       method: config.method.toUpperCase(),
  10.       header: config.headers,
  11.       readTimeout: config.timeout,
  12.       connectTimeout: config.timeout,
  13.       extraData: config.data ? JSON.stringify(config.data) : undefined
  14.     };
  15.     // 发起请求
  16.     httpRequest.request(
  17.       config.url,
  18.       requestConfig,
  19.       (err, data) => {
  20.         if (!err) {
  21.           resolve({
  22.             data: data.result,
  23.             status: data.responseCode,
  24.             headers: data.header,
  25.             config: config
  26.           });
  27.         } else {
  28.           reject(new AxiosError(
  29.             'Request failed',
  30.             'ECONNABORTED',
  31.             config,
  32.             httpRequest,
  33.             err
  34.           ));
  35.         }
  36.       }
  37.     );
  38.   });
  39. }
复制代码
      
                       剖析:
     
     3.1.2 文件下载适配器

                                   登录后复制                        
  1. // library/src/main/ets/components/lib/adapters/ohos/download.js
  2. import request from '@ohos.request';
  3. export default function downloadAdapter(config) {
  4.   return new Promise((resolve, reject) => {
  5.     const downloadConfig = {
  6.       url: config.url,
  7.       header: config.headers,
  8.       filePath: config.filePath
  9.     };
  10.     request.downloadFile(context, downloadConfig)
  11.       .then((downloadTask) => {
  12.         // 监听下载进度
  13.         downloadTask.on('progress', (receivedSize, totalSize) => {
  14.           if (config.onDownloadProgress) {
  15.             config.onDownloadProgress({
  16.               loaded: receivedSize,
  17.               total: totalSize
  18.             });
  19.           }
  20.         });
  21.         // 监听下载完成
  22.         downloadTask.on('complete', (uri) => {
  23.           resolve({
  24.             data: uri,
  25.             status: 200,
  26.             config: config
  27.           });
  28.         });
  29.       })
  30.       .catch(error => {
  31.         reject(new AxiosError(
  32.           'Download failed',
  33.           'DOWNLOAD_ERROR',
  34.           config,
  35.           null,
  36.           error
  37.         ));
  38.       });
  39.   });
  40. }
复制代码
      
                       剖析:
     
     3.1.3 文件上传适配器

                                   登录后复制                        
  1. // library/src/main/ets/components/lib/adapters/ohos/upload.js
  2. import request from '@ohos.request';
  3. export default function uploadAdapter(config) {
  4.   return new Promise((resolve, reject) => {
  5.     const uploadConfig = {
  6.       url: config.url,
  7.       header: config.headers,
  8.       method: config.method,
  9.       files: [],
  10.       data: []
  11.     };
  12.     // 处理 FormData
  13.     if (config.data instanceof FormData) {
  14.       config.data.forEach((value, key) => {
  15.         if (value instanceof File) {
  16.           uploadConfig.files.push({
  17.             filename: value.name,
  18.             name: key,
  19.             uri: value.uri,
  20.             type: value.type
  21.           });
  22.         } else {
  23.           uploadConfig.data.push({
  24.             name: key,
  25.             value: value
  26.           });
  27.         }
  28.       });
  29.     }
  30.     request.uploadFile(context, uploadConfig)
  31.       .then((uploadTask) => {
  32.         // 监听上传进度
  33.         uploadTask.on('progress', (uploadedSize, totalSize) => {
  34.           if (config.onUploadProgress) {
  35.             config.onUploadProgress({
  36.               loaded: uploadedSize,
  37.               total: totalSize
  38.             });
  39.           }
  40.         });
  41.         // 监听上传完成
  42.         uploadTask.on('complete', (response) => {
  43.           resolve({
  44.             data: response,
  45.             status: 200,
  46.             config: config
  47.           });
  48.         });
  49.       })
  50.       .catch(error => {
  51.         reject(new AxiosError(
  52.           'Upload failed',
  53.           'UPLOAD_ERROR',
  54.           config,
  55.           null,
  56.           error
  57.         ));
  58.       });
  59.   });
  60. }
复制代码
      
                       剖析:
     
     3.2 拦截器实现

                                   登录后复制                        
  1. // 请求拦截器
  2. axios.interceptors.request.use(
  3.   config => {
  4.     // 在发送请求之前做些什么
  5.     config.headers['Authorization'] = `Bearer ${getToken()}`;
  6.     return config;
  7.   },
  8.   error => {
  9.     // 对请求错误做些什么
  10.     return Promise.reject(error);
  11.   }
  12. );
  13. // 响应拦截器
  14. axios.interceptors.response.use(
  15.   response => {
  16.     // 对响应数据做点什么
  17.     return response.data;
  18.   },
  19.   error => {
  20.     // 对响应错误做点什么
  21.     if (error.response.status === 401) {
  22.       // 处理认证错误
  23.     }
  24.     return Promise.reject(error);
  25.   }
  26. );
复制代码
      
                       剖析:
     
     四、高级特性

     4.1 并发哀求

                                   登录后复制                        
  1. async function makeMultipleRequests() {
  2.   try {
  3.     const [users, posts] = await Promise.all([
  4.       axios.get('/users'),
  5.       axios.get('/posts')
  6.     ]);
  7.    
  8.     console.info('Users:', users.data);
  9.     console.info('Posts:', posts.data);
  10.   } catch (error) {
  11.     console.error('Error:', error);
  12.   }
  13. }
复制代码
      
                       剖析:
     
     4.2 哀求配置

                                   登录后复制                        
  1. const instance = axios.create({
  2.   baseURL: 'https://api.example.com',
  3.   timeout: 5000,
  4.   headers: {
  5.     'Content-Type': 'application/json'
  6.   },
  7.   // 自定义转换数据
  8.   transformRequest: [(data) => {
  9.     // 对发送的数据进行转换
  10.     return JSON.stringify(data);
  11.   }],
  12.   transformResponse: [(data) => {
  13.     // 对接收的数据进行转换
  14.     return JSON.parse(data);
  15.   }]
  16. });
复制代码
      
                       剖析:
     
     4.3 错误处理处罚

                                   登录后复制                        
  1. async function handleRequestWithError() {
  2.   try {
  3.     await axios.get('/api/data');
  4.   } catch (error) {
  5.     if (error.response) {
  6.       // 服务器返回错误状态码
  7.       console.error('Status:', error.response.status);
  8.       console.error('Data:', error.response.data);
  9.     } else if (error.request) {
  10.       // 请求已发送但没有收到响应
  11.       console.error('No response:', error.request);
  12.     } else {
  13.       // 请求配置出错
  14.       console.error('Error:', error.message);
  15.     }
  16.   }
  17. }
复制代码
      
                       剖析:
     
     五、最佳实践

     5.1 封装 API 服务

                                   登录后复制                        
  1. // api/index.ets
  2. import axios from '@ohos/axios';
  3. const api = axios.create({
  4.   baseURL: 'https://api.example.com',
  5.   timeout: 5000
  6. });
  7. export const userService = {
  8.   getUser: (id: string) => api.get(`/users/${id}`),
  9.   createUser: (userData: any) => api.post('/users', userData),
  10.   updateUser: (id: string, userData: any) => api.put(`/users/${id}`, userData),
  11.   deleteUser: (id: string) => api.delete(`/users/${id}`)
  12. };
复制代码
      
                       剖析:
     
     5.2 统一错误处理处罚

     在 API 哀求中,统一错误处理处罚是非常重要的,它可以资助我们更好地管理和相应应用步伐中的非常。通过利用 axios 的拦截器功能,我们可以会合地处理处罚全部的哀求和相应错误,从而简化代码逻辑,进步代码的可维护性。
     5.2.1 错误拦截器的实现

     在 setupErrorHandler 函数中,我们定义了一个相应拦截器,该拦截器会检查每个相应的状态码,并根据状态码执行相应的错误处理处罚逻辑。
                                   登录后复制                        
  1. // utils/errorHandler.ets
  2. import axios from '@ohos/axios';
  3. export function setupErrorHandler(axiosInstance) {
  4.   axiosInstance.interceptors.response.use(
  5.     (response) => {
  6.       // 如果请求成功,直接返回响应数据
  7.       return response;
  8.     },
  9.     (error) => {
  10.       // 如果请求失败,处理错误
  11.       if (error.response) {
  12.         // 服务器返回了错误状态码
  13.         switch (error.response.status) {
  14.           case 401:
  15.             // 处理未授权错误
  16.             console.error('未授权访问,请重新登录');
  17.             // 例如,可以重定向到登录页面
  18.             // navigateToLogin();
  19.             break;
  20.           case 403:
  21.             // 处理禁止访问错误
  22.             console.error('禁止访问该资源');
  23.             // 可以显示一个禁止访问的提示
  24.             // showAlert('禁止访问该资源');
  25.             break;
  26.           case 404:
  27.             // 处理资源未找到错误
  28.             console.error('请求的资源未找到');
  29.             // 可以显示一个资源未找到的提示
  30.             // showAlert('请求的资源未找到');
  31.             break;
  32.           case 500:
  33.             // 处理服务器内部错误
  34.             console.error('服务器内部错误');
  35.             // 可以显示一个服务器错误的提示
  36.             // showAlert('服务器内部错误');
  37.             break;
  38.           default:
  39.             // 处理其他状态码的错误
  40.             console.error('未知错误:', error.response.status, error.response.data);
  41.             // 可以显示一个通用的错误提示
  42.             // showAlert('未知错误');
  43.             break;
  44.         }
  45.       } else if (error.request) {
  46.         // 请求已发送但没有收到响应
  47.         console.error('请求超时或网络问题');
  48.         // 可以显示一个请求超时或网络问题的提示
  49.         // showAlert('请求超时或网络问题');
  50.       } else {
  51.         // 请求配置出错
  52.         console.error('请求配置错误:', error.message);
  53.         // 可以显示一个请求配置错误的提示
  54.         // showAlert('请求配置错误');
  55.       }
  56.       // 继续向下抛出错误,以便上层代码可以处理
  57.       return Promise.reject(error);
  58.     }
  59.   );
  60. }
复制代码
      
                       5.2.2 利用错误拦截器

     在创建 axios 实例时,我们可以调用 setupErrorHandler 函数来设置错误拦截器。
                                   登录后复制                        
  1. // api/index.ets
  2. import axios from '@ohos/axios';
  3. import { setupErrorHandler } from './utils/errorHandler';
  4. const api = axios.create({
  5.   baseURL: 'https://api.example.com',
  6.   timeout: 5000
  7. });
  8. // 设置错误拦截器
  9. setupErrorHandler(api);
  10. export const userService = {
  11.   getUser: (id: string) => api.get(`/users/${id}`),
  12.   createUser: (userData: any) => api.post('/users', userData),
  13.   updateUser: (id: string, userData: any) => api.put(`/users/${id}`, userData),
  14.   deleteUser: (id: string) => api.delete(`/users/${id}`)
  15. };
复制代码
      
                       5.2.2.1 axios.create 的配置

                                   登录后复制                        
  1. const api = axios.create({
  2.   baseURL: 'https://api.example.com',
  3.   timeout: 5000
  4. });
复制代码
      
                       
     5.2.2.2 设置错误拦截器

                                   登录后复制                        
  1. setupErrorHandler(api);
复制代码
      
                       这行代码调用了 setupErrorHandler 函数,并将 axios 实例 api 作为参数传递。setupErrorHandler 函数会在 api 实例上添加一个相应拦截器。
     5.2.2.3 相应拦截器的逻辑

                                   登录后复制                        
  1. axiosInstance.interceptors.response.use(
  2.   (response) => {
  3.     // 如果请求成功,直接返回响应数据
  4.     return response;
  5.   },
  6.   (error) => {
  7.     // 如果请求失败,处理错误
  8.     if (error.response) {
  9.       // 服务器返回了错误状态码
  10.       switch (error.response.status) {
  11.         case 401:
  12.           // 处理未授权错误
  13.           console.error('未授权访问,请重新登录');
  14.           // 例如,可以重定向到登录页面
  15.           // navigateToLogin();
  16.           break;
  17.         case 403:
  18.           // 处理禁止访问错误
  19.           console.error('禁止访问该资源');
  20.           // 可以显示一个禁止访问的提示
  21.           // showAlert('禁止访问该资源');
  22.           break;
  23.         case 404:
  24.           // 处理资源未找到错误
  25.           console.error('请求的资源未找到');
  26.           // 可以显示一个资源未找到的提示
  27.           // showAlert('请求的资源未找到');
  28.           break;
  29.         case 500:
  30.           // 处理服务器内部错误
  31.           console.error('服务器内部错误');
  32.           // 可以显示一个服务器错误的提示
  33.           // showAlert('服务器内部错误');
  34.           break;
  35.         default:
  36.           // 处理其他状态码的错误
  37.           console.error('未知错误:', error.response.status, error.response.data);
  38.           // 可以显示一个通用的错误提示
  39.           // showAlert('未知错误');
  40.           break;
  41.       }
  42.     } else if (error.request) {
  43.       // 请求已发送但没有收到响应
  44.       console.error('请求超时或网络问题');
  45.       // 可以显示一个请求超时或网络问题的提示
  46.       // showAlert('请求超时或网络问题');
  47.     } else {
  48.       // 请求配置出错
  49.       console.error('请求配置错误:', error.message);
  50.       // 可以显示一个请求配置错误的提示
  51.       // showAlert('请求配置错误');
  52.     }
  53.     // 继续向下抛出错误,以便上层代码可以处理
  54.     return Promise.reject(error);
  55.   }
  56. );
复制代码
      
                       
     
     5.2.3 重试机制

     在实际应用中,我们可能希望在某些环境下自动重试哀求,比方网络不稳固时。我们可以通过扩展错误拦截器来实现这一功能。
                                   登录后复制                        
  1. // utils/errorHandler.ets
  2. export function setupErrorHandler(axiosInstance) {
  3.   let retryCount = 0;
  4.   const maxRetries = 3;
  5.   axiosInstance.interceptors.response.use(
  6.     (response) => {
  7.       return response;
  8.     },
  9.     (error) => {
  10.       const originalRequest = error.config;
  11.       if (error.response) {
  12.         switch (error.response.status) {
  13.           case 401:
  14.             console.error('未授权访问,请重新登录');
  15.             // 例如,可以重定向到登录页面
  16.             // navigateToLogin();
  17.             break;
  18.           case 403:
  19.             console.error('禁止访问该资源');
  20.             // 可以显示一个禁止访问的提示
  21.             // showAlert('禁止访问该资源');
  22.             break;
  23.           case 404:
  24.             console.error('请求的资源未找到');
  25.             // 可以显示一个资源未找到的提示
  26.             // showAlert('请求的资源未找到');
  27.             break;
  28.           case 500:
  29.             console.error('服务器内部错误');
  30.             // 可以显示一个服务器错误的提示
  31.             // showAlert('服务器内部错误');
  32.             break;
  33.           default:
  34.             console.error('未知错误:', error.response.status, error.response.data);
  35.             // 可以显示一个通用的错误提示
  36.             // showAlert('未知错误');
  37.             break;
  38.         }
  39.       } else if (error.request) {
  40.         console.error('请求超时或网络问题');
  41.         // 可以显示一个请求超时或网络问题的提示
  42.         // showAlert('请求超时或网络问题');
  43.         // 重试机制
  44.         if (retryCount < maxRetries) {
  45.           retryCount++;
  46.           return axiosInstance(originalRequest);
  47.         }
  48.       } else {
  49.         console.error('请求配置错误:', error.message);
  50.         // 可以显示一个请求配置错误的提示
  51.         // showAlert('请求配置错误');
  52.       }
  53.       // 继续向下抛出错误,以便上层代码可以处理
  54.       return Promise.reject(error);
  55.     }
  56.   );
  57.   // 重置重试计数器
  58.   axiosInstance.interceptors.request.use(
  59.     (config) => {
  60.       retryCount = 0;
  61.       return config;
  62.     },
  63.     (error) => {
  64.       return Promise.reject(error);
  65.     }
  66.   );
  67. }
复制代码
      
                       
     5.2.4 自定义错误处理处罚

     在某些环境下,我们可能希望为差别的 API 提供差别的错误处理处罚逻辑。我们可以通过在服务层定义自定义的错误处理处罚函数来实现这一点。
                                   登录后复制                        
  1. // api/index.etsimport axios from '@ohos/axios';import { setupErrorHandler } from './utils/errorHandler';const api = axios.create({
  2.   baseURL: 'https://api.example.com',
  3.   timeout: 5000
  4. });// 设置默认错误拦截器setupErrorHandler(api);// 自定义错误处理处罚api.interceptors.response.use(  (response) => {    return response;  },  (error) => {    if (error.config && error.config.customErrorHandling) {      // 调用自定义错误处理处罚函数      error.config.customErrorHandling(error);    }    return Promise.reject(error);  });export const userService = {  getUser: (id: string) => api.get(`/users/${id}`, {    customErrorHandling: (error) => {      console.error('自定义错误处理处罚:', error);      // 可以在这里添加自定义的错误处理处罚逻辑    }  }),  createUser: (userData: any) => api.post('/users', userData),  updateUser: (id: string, userData: any) => api.put(`/users/${id}`, userData),  deleteUser: (id: string) => api.delete(`/users/${id}`)};
复制代码
      
                       

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4