【HarmonyOS开发】ArkTS HTTP 工具类封装

前言

在鸿蒙系统中进行网络请求是应用开发中的一个常见需求。本文将详细介绍如何使用自定义的MyHttpUtil类来简化HTTP请求的实现,并探讨其具体实现细节。MyHttpUtil是基于鸿蒙系统的ArkTS编写的一个实用工具类,可以有效地管理和发起HTTP请求。

1. 背景

在现代应用开发中,网络请求是必不可少的一部分。无论是获取远程数据还是提交用户信息,都需要通过HTTP请求与服务器进行通信。鸿蒙系统提供了强大的网络库,但直接使用这些库进行网络请求可能会显得繁琐且易出错。因此,封装一个通用的HTTP请求工具类可以大大简化开发过程。

2. MyHttpUtil类的实现

导入必要模块

首先,我们需要导入一些必要的模块,包括HTTP库、全局数据、偏好设置工具、日志工具、吐司工具等:

import http from '@ohos.net.http';
import GlobalData from '../global/GlobalData';
import PreferenceKey from '../preference/PreferenceKey';
import PreferencesUtil from '../preference/PreferencesUtil';
import DebugLogUtil, { LogStyle } from '../utils/DebugLogUtil';
import ToastUtils from '../utils/ToastUtils';
import HttpConnectAPI from './HttpConnectAPI';

定义请求方法和URL类型枚举

接下来,我们定义一些常用的请求方法和基础URL类型:

export enum RequestMethod {
  OPTIONS = "OPTIONS",
  GET = "GET",
  HEAD = "HEAD",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE",
  TRACE = "TRACE",
  CONNECT = "CONNECT"
}

export enum BaseURLType {
  COMMON,
  SPECIAL
}

MyHttpUtil类的静态属性和方法

我们定义了静态属性和方法,用于配置和发起HTTP请求:

export class MyHttpUtil {
  private static readonly LOG_TAG: string = "====MyHttpUtil====";
  private static httpInstance = http.createHttp();
  public static READ_TIME_OUT: number = 60000; // 单位:毫秒
  public static CONNECT_TIME_OUT: number = 60000; // 单位:毫秒

  public static async makeRequest(
    url: string,
    method: RequestMethod,
    data: Record<string, number | string>,
    mBaseURLType: BaseURLType,
    showErrorToast: boolean = false,
    successCallback: (result: Record<string, any>) => void,
    errorCallback: (error: string) => void
  ): Promise<void> {
    // 确保 URL 有效
    if (!url) {
      errorCallback('URL 不能为空');
      return;
    }

    // 检查并获取用户的Token和OpenID
    if (!GlobalData.getInstance().USER_INFO_TOKEN || !GlobalData.getInstance().USER_INFO_OPEN_ID) {
      GlobalData.getInstance().USER_INFO_TOKEN = await PreferencesUtil.getInstance().get(PreferenceKey.USER_INFO_TOKEN_VALUE, '') as string;
      GlobalData.getInstance().USER_INFO_OPEN_ID = await PreferencesUtil.getInstance().get(PreferenceKey.USER_INFO_OPEN_ID_VALUE, '') as string;
    }

    // 配置请求头
    let mHeaderMap: Record<string, string> = {
      'content-type': 'application/json;charset=UTF-8',
      'connection': 'keep-alive',
      'accessToken': GlobalData.getInstance().USER_INFO_TOKEN,
      'openId': GlobalData.getInstance().USER_INFO_OPEN_ID,
      'version': GlobalData.getInstance().API_VERSION
    };

    // 配置请求选项
    let options: http.HttpRequestOptions = {
      method: method,
      header: mHeaderMap,
      readTimeout: MyHttpUtil.READ_TIME_OUT,
      connectTimeout: MyHttpUtil.CONNECT_TIME_OUT,
      extraData: method !== RequestMethod.GET ? JSON.stringify(data) : undefined,
    };

    // 根据URL类型选择基础URL
    switch (mBaseURLType) {
      case BaseURLType.COMMON:
        url = HttpConnectAPI.BaseIOVURL + url;
        break;
      case BaseURLType.SPECIAL:
        break;
      default:
        url = HttpConnectAPI.BaseIOVURL + url;
    }

    // 处理GET请求的查询参数
    if (method === RequestMethod.GET && Object.keys(data).length > 0) {
      let queryString = Object.keys(data).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join('&');
      url += `?${queryString}`;
    }

    try {
      // 发起HTTP请求
      let response: http.HttpResponse = await MyHttpUtil.httpInstance.request(url, options);
      let result: Record<string, any> = JSON.parse(response.result.toString());

      DebugLogUtil.log(LogStyle.LEVEL_DEBUG, MyHttpUtil.LOG_TAG, `url====${url}====method====${method}====header====${JSON.stringify(response.header)}====responseCode====${response.responseCode}`);

      // 处理成功响应
      if (response.responseCode === 200) {
        DebugLogUtil.log(LogStyle.LEVEL_DEBUG, MyHttpUtil.LOG_TAG, `url====${url}====method====${method}====header====${JSON.stringify(response.header)}====responseCode====${response.responseCode}====Data====${JSON.stringify(result)}`);
        successCallback(result);
      } else {
        // 处理错误响应
        if (showErrorToast) {
          ToastUtils.showToast('接口业务错误信息');
        }
        DebugLogUtil.log(LogStyle.LEVEL_ERROR, MyHttpUtil.LOG_TAG, `url====${url}====method====${method}====header====${JSON.stringify(response.header)}====ErrorResponseCode====${response.responseCode}`);
        errorCallback(response.responseCode.toString());
      }
    } catch (error) {
      // 处理请求异常
      DebugLogUtil.log(LogStyle.LEVEL_ERROR, MyHttpUtil.LOG_TAG, `url====${url}====method====${method}====Exception====${error}`);
      errorCallback(error);
    }
  }
}

3. 代码详解

导入必要模块:
我们首先导入了鸿蒙系统的HTTP库以及一些实用工具模块。

请求方法和URL类型枚举:
定义了HTTP请求的各种方法(如GET、POST等)和基础URL类型(COMMON和SPECIAL)。

静态属性和方法:

  • LOG_TAG:用于日志记录的标签。
  • httpInstance:创建一个HTTP实例用于发起请求。
  • READ_TIME_OUTCONNECT_TIME_OUT:配置请求的超时时间。
  • makeRequest方法:核心方法,用于发起HTTP请求。

请求头和选项配置:
makeRequest方法中,我们首先确保URL有效,然后检查用户的Token和OpenID,并配置请求头和选项。

基础URL选择:
根据不同的基础URL类型选择合适的URL。

处理GET请求的查询参数:
对于GET请求,我们将查询参数附加到URL上。

发起HTTP请求并处理响应:
使用httpInstance发起请求,并处理成功和失败的响应,进行日志记录和错误处理。

4. 使用示例

import http from '@ohos.net.http';
import GlobalData from '../global/GlobalData';
import PreferenceKey from '../preference/PreferenceKey';
import PreferencesUtil from '../preference/PreferencesUtil';
import DebugLogUtil, { LogStyle } from '../utils/DebugLogUtil';
import ToastUtils from '../utils/ToastUtils';
import HttpConnectAPI from './HttpConnectAPI';

export enum RequestMethod {
  OPTIONS = "OPTIONS",
  GET = "GET",
  HEAD = "HEAD",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE",
  TRACE = "TRACE",
  CONNECT = "CONNECT"
}

export enum BaseURLType {
  COMMON,
  SPECIAL
}

export class MyHttpUtil {
  private static readonly LOG_TAG: string = "====MyHttpUtil====";
  private static httpInstance = http.createHttp();
  public static READ_TIME_OUT: number = 60 1000
  public static CONNECT_TIME_OUT: number = 60 1000

  public static async makeRequest(
    url: string,
    method: http.RequestMethod,
    data: Record<string, number | string,
    mBaseURLType: BaseURLType,
    showErrorToast: boolean = false,
    successCallback: (result: Record<string, Object) => void,
    errorCallback: (error: string) => void
  ): Promise<void{
    // 确保 URL 有效
    if (!url) {
      errorCallback('URL 不能为空');
      return;
    }

    if(GlobalData.getInstance().USER_INFO_TOKEN == null || GlobalData.getInstance().USER_INFO_TOKEN.length == 0 || GlobalData.getInstance().USER_INFO_OPEN_ID == null || GlobalData.getInstance().USER_INFO_OPEN_ID.length == 0){
      GlobalData.getInstance().USER_INFO_TOKEN = await PreferencesUtil.getInstance().get(PreferenceKey.USER_INFO_TOKEN_VALUE, '') as string
      GlobalData.getInstance().USER_INFO_OPEN_ID = await PreferencesUtil.getInstance().get(PreferenceKey.USER_INFO_OPEN_ID_VALUE, '') as string
    }

    let mHeaderMap: Record<string, number | string= {
      'content-type': 'application/json;charset=UTF-8',
      'connection': 'keep-alive',
      'accessToken': GlobalData.getInstance().USER_INFO_TOKEN,
      'openId': GlobalData.getInstance().USER_INFO_OPEN_ID,
      'version': GlobalData.getInstance().API_VERSION
    };

    let options: http.HttpRequestOptions = {
      method: method,
      header: mHeaderMap,
      readTimeout: MyHttpUtil.READ_TIME_OUT,
      connectTimeout: MyHttpUtil.CONNECT_TIME_OUT,
      extraData: method != http.RequestMethod.GET ? JSON.stringify(data) : undefined, // 根据请求方法设置数据参数
    };

    switch (mBaseURLType) {
      case BaseURLType.COMMON:
        url = HttpConnectAPI.BaseIOVURL url
        break;
      case BaseURLType.SPECIAL:
        url = url
        break;
      default:
        url = HttpConnectAPI.BaseIOVURL url
    }

    // 如果是 GET 请求,并且有查询参数,则将查询参数附加到 URL 上
    if (method === http.RequestMethod.GET && Object.keys(data).length 0) {
      let queryString = Object.keys(data).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join('&');
      url += `?${queryString}`;
    }

    try {
      // 使用同一个 http 实例发起请求
      let response: http.HttpResponse = await MyHttpUtil.httpInstance.request(url, options);
      let result:Record<string, Object= JSON.parse(response.result.toString());

      DebugLogUtil.log(LogStyle.LEVEL_DEBUG, MyHttpUtil.LOG_TAG,'url====' url '====method====' method '====header====' JSON.stringify(response.header) '====responseCode====' response.responseCode);

      // 处理成功响应
      if (response.responseCode === 200) {
        DebugLogUtil.log(LogStyle.LEVEL_DEBUG, MyHttpUtil.LOG_TAG,'url====' url '====method====' method '====header====' JSON.stringify(response.header) '====responseCode====' response.responseCode '====Data====' +JSON.stringify(result));
        successCallback(result);
      } else {
        // 处理错误响应
        if (showErrorToast) {
          ToastUtils.showToast('接口业务错误信息');
        }
        DebugLogUtil.log(LogStyle.LEVEL_ERROR, MyHttpUtil.LOG_TAG,'url====' url '====method====' method '====header====' JSON.stringify(response.header) '====ErrorResponseCode====' response.responseCode);
        errorCallback(response.responseCode.toString());
      }
    } catch (error) {
      // 处理请求异常
      DebugLogUtil.log(LogStyle.LEVEL_ERROR, MyHttpUtil.LOG_TAG,'url====' url '====method====' method '====Exception====' error);
      errorCallback(error);
    }
  }

}

下面是一个使用MyHttpUtil类发起GET请求的示例:

async userLoginResult(userPhone: string, userPassword: string) {
    let params: Record<string, number | string> = {
      'phone': userPhone.toString(),
      'password': passwordDigest.toString(),
    };
await MyHttpUtil.makeRequest(HttpConnectAPI.API_USER_LOGIN, RequestMethod.GET, params, BaseURLType.COMMON, false,
  async (result) => {
    this.mLoginModelBean = JSON.parse(JSON.stringify(result))
  }, (error) => {
    this.mCustomDialogController.close()

    ToastUtils.showToast($r('app.string.toast_login_page_content3'))
  })
}

在这个示例中,我们调用了makeRequest方法,传入了请求的URL、方法、参数、URL类型和回调函数。

5. 总结

通过封装一个通用的HTTP请求工具类MyHttpUtil,我们可以在鸿蒙系统中更方便地进行网络请求。该工具类不仅简化了请求的配置和处理,还提供了日志记录和错误处理的功能,极大地提高了开发效率和代码的可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Android程序Su

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值