【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);
};
相关推荐
西洼工作室6 小时前
高效管理搜索历史:Vue持久化实践
前端·javascript·vue.js
广州华水科技6 小时前
北斗形变监测传感器在水库安全中的应用及技术优势分析
前端
开发者如是说7 小时前
Compose 开发桌面程序的一些问题
前端·架构
旺代7 小时前
Token 存储与安全防护
前端
洋不写bug8 小时前
html实现简历信息填写界面
前端·html
三十_A8 小时前
【无标题】
前端·后端·node.js
excel8 小时前
Vue 编译器源码解读:transformVBindShorthand 的设计与原理
前端
时间的情敌8 小时前
Vue3的异步DOM更新:nextTick的正确使用方法
前端·javascript·vue.js
风语者日志8 小时前
[LitCTF 2023]作业管理系统
前端·网络·安全·web安全·ctf
excel9 小时前
深入解析:Vue 编译器核心工具函数源码(compiler-core/utils.ts)
前端