【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);
};
相关推荐
玩电脑的辣条哥2 小时前
Python如何播放本地音乐并在web页面播放
开发语言·前端·python
ew452182 小时前
ElementUI表格表头自定义添加checkbox,点击选中样式不生效
前端·javascript·elementui
suibian52352 小时前
AI时代:前端开发的职业发展路径拓宽
前端·人工智能
Moon.92 小时前
el-table的hasChildren不生效?子级没数据还显示箭头号?树形数据无法展开和收缩
前端·vue.js·html
垚垚 Securify 前沿站2 小时前
深入了解 AppScan 工具的使用:筑牢 Web 应用安全防线
运维·前端·网络·安全·web安全·系统安全
工业甲酰苯胺5 小时前
Vue3 基础概念与环境搭建
前端·javascript·vue.js
mosquito_lover16 小时前
怎么把pyqt界面做的像web一样漂亮
前端·python·pyqt
遇到困难睡大觉哈哈7 小时前
鸿蒙Harmony-UIAbility内状态-LocalStorage详细介绍
华为·harmonyos·鸿蒙
MarkHD8 小时前
第十六天 HarmonyOS WebView开发实战:从加载网页到与JavaScript交互
javascript·交互·harmonyos
柴柴的小记9 小时前
前端vue引入特殊字体不生效
前端·javascript·vue.js