【HarmonyOS Next】封装一个网络请求模块

【HarmonyOS Next】封装一个网络请求模块

环境准备

在开始之前,确保你已经安装了以下依赖:

  • @ohos/axios:用于发起 HTTP 请求。
  • @ohos.router:用于页面跳转。
  • @kit.ArkUI:用于显示提示信息。
  • @kit.ArkTS:用于 JSON 操作。

安装方法:

bash 复制代码
npm install @ohos/axios @ohos.router @kit.ArkUI @kit.ArkTS

封装步骤

1. 导入依赖

首先,我们需要导入所需的模块:

typescript 复制代码
import axios, { InternalAxiosRequestConfig, AxiosResponse, AxiosError, AxiosRequestConfig, AxiosInstance } from '@ohos/axios';
import router from '@ohos.router';
import { promptAction } from '@kit.ArkUI';
import PreferencesUtils from './PreferencesUtils';
import { JSON } from '@kit.ArkTS';

2. 定义 API 响应接口

为了更好地处理 API 响应,我们定义一个泛型接口 ApiResponse

typescript 复制代码
interface ApiResponse<T> {
  data: T;
  message?: string;
  code?: string; // 统一为字符串类型
  msg?: string;
}

3. 创建 axios 实例

创建一个 axios 实例,并设置基础 URL、超时时间和默认请求头:

typescript 复制代码
const instance: AxiosInstance = axios.create({
  baseURL: 'https://zhdj.changhong.com',
  timeout: 10000, // 10秒超时
  headers: { 'Content-Type': 'application/json' },
});

4. 设置请求拦截器

在请求发送前,我们可以对请求配置进行修改,例如添加 token 和其他公共请求头:

typescript 复制代码
instance.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
  console.log('instance.interceptors.request:', JSON.stringify(config));

  // 从 PreferencesUtils 中异步获取 token
  const token = await PreferencesUtils.get("token");
  console.log('instance.interceptors.request:token:', token);

  if (token) {
    config.headers['Authorization'] = "Bearer " + token; // 设置 token
    config.headers['System-id'] = "3";
  }

  return config;
}, (error: AxiosError) => {
  // 请求错误处理
  return Promise.reject(error);
});

5. 设置响应拦截器

在响应返回后,我们可以对响应数据进行处理,例如根据状态码显示提示信息或跳转到登录页面:

typescript 复制代码
instance.interceptors.response.use((response: AxiosResponse) => {
  console.log('cwx-response:', JSON.stringify(response));

  // 根据项目的实际情况处理响应
  if (response?.data?.code === '500') {
    promptAction.showToast({
      message: response.data.message, // 修正拼写错误
      duration: 500,
      alignment: Alignment.Center
    });
    return Promise.reject(response.data);
  }

  if (response?.data?.code === '200') {
    return Promise.resolve(response.data);
  }

  return response.data;
}, (error: AxiosError) => {
  console.log('AxiosError:', JSON.stringify(error.response));

  const status = error.response?.status;
  switch (status) {
    case 401: // 无权限未登录
      router.pushUrl({
        url: 'pages/login'
      });
      break;
    default:
      promptAction.showToast({
        message: '系统异常,请稍后再试!',
        duration: 2000,
        alignment: Alignment.Center
      });
      break;
  }

  return Promise.reject(error);
});

6. 封装请求方法

最后,我们将所有逻辑封装在一个泛型函数中,以便在应用中方便地调用:

typescript 复制代码
// 暴露封装请求--每次调用这个方法时,不会重复添加拦截器
export default <T>(config: AxiosRequestConfig): Promise<ApiResponse<T>> => {
  return instance(config);
};

使用示例

封装完成后,我们可以在应用中轻松使用这个网络请求模块。以下是一个简单的示例:

typescript 复制代码
import request from './request';

const getUserInfo = async (): Promise<ApiResponse<User>> => {
  const response = await request({
    url: '/api/user/info',
    method: 'GET',
  });

  return response;
};

const postData = async (data: PostData): Promise<ApiResponse<PostResponse>> => {
  const response = await request({
    url: '/api/data/post',
    method: 'POST',
    data: data,
  });

  return response;
};

// 调用示例
getUserInfo().then(userInfo => {
  console.log('用户信息:', JSON.stringify(userInfo));
}).catch(error => {
  console.error('获取用户信息失败:', error);
});

postData({ title: '测试标题', content: '测试内容' }).then(postResponse => {
  console.log('数据提交成功:', JSON.stringify(postResponse));
}).catch(error => {
  console.error('数据提交失败:', error);
});

总结

通过上述步骤,我们成功地在鸿蒙 Next 中封装了一个强大的网络请求模块。这个模块不仅简化了网络请求的代码,还通过请求和响应拦截器增强了请求的健壮性和用户体验。


附录:完整代码

typescript 复制代码
import axios, { InternalAxiosRequestConfig, AxiosResponse, AxiosError, AxiosRequestConfig, AxiosInstance } from '@ohos/axios';
import router from '@ohos.router';
import { promptAction } from '@kit.ArkUI';
import PreferencesUtils from './PreferencesUtils';
import { JSON } from '@kit.ArkTS';

interface ApiResponse<T> {
  data: T;
  message?: string;
  code?: string; // 统一为字符串类型
  msg?: string;
}

// 创建 axios 实例
const instance: AxiosInstance = axios.create({
  baseURL: 'https://zhdj.changhong.com',
  timeout: 10000, // 10秒超时
  headers: { 'Content-Type': 'application/json' },
});

// 设置请求拦截器
instance.interceptors.request.use(async (config: InternalAxiosRequestConfig) => {
  console.log('instance.interceptors.request:', JSON.stringify(config));

  // 从 PreferencesUtils 中异步获取 token
  const token = await PreferencesUtils.get("token");
  console.log('instance.interceptors.request:token:', token);

  if (token) {
    config.headers['Authorization'] = "Bearer " + token; // 设置 token
    config.headers['System-id'] = "3";
  }

  return config;
}, (error: AxiosError) => {
  // 请求错误处理
  return Promise.reject(error);
});

// 设置响应拦截器
instance.interceptors.response.use((response: AxiosResponse) => {
  console.log('cwx-response:', JSON.stringify(response));

  // 根据项目的实际情况处理响应
  if (response?.data?.code === '500') {
    promptAction.showToast({
      message: response.data.message, // 修正拼写错误
      duration: 500,
      alignment: Alignment.Center
    });
    return Promise.reject(response.data);
  }

  if (response?.data?.code === '200') {
    return Promise.resolve(response.data);
  }

  return response.data;
}, (error: AxiosError) => {
  console.log('AxiosError:', JSON.stringify(error.response));

  const status = error.response?.status;
  switch (status) {
    case 401: // 无权限未登录
      router.pushUrl({
        url: 'pages/login'
      });
      break;
    default:
      promptAction.showToast({
        message: '系统异常,请稍后再试!',
        duration: 2000,
        alignment: Alignment.Center
      });
      break;
  }

  return Promise.reject(error);
});

// 暴露封装请求--每次调用这个方法时,不会重复添加拦截器
export default <T>(config: AxiosRequestConfig): Promise<ApiResponse<T>> => {
  return instance(config);
};
相关推荐
轻口味1 小时前
命名空间与模块化概述
开发语言·前端·javascript
前端小小王2 小时前
React Hooks
前端·javascript·react.js
迷途小码农零零发2 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀3 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef5 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6415 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻5 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云5 小时前
npm淘宝镜像
前端·npm·node.js