HarmonyOS NEXT 基于 axios 和 Promise 的网络框架封装

一、前言

本文采用axios 网络请求框架进行封装,便于后续开发,参考文档

API : API Version 12 Beta5
Dev : 5.0.3.700
axios: “2.2.0”

二、详细代码

1.在项目的oh-package.json5文件中引入axios依赖
在这里插入图片描述

"@ohos/axios": "2.2.0"

2.在主App的module.json5增加网络请求权限
在这里插入图片描述

 "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      
    ],

3.主要工具类HttpUtil

/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, Method } from '@ohos/axios';

import { Log } from '../utils/Log';
import { systemDateTime } from '@kit.BasicServicesKit';
import ResponseResult from './ResponseResult';
import { StringBuilder } from '../utils/StringBuilder';
import { HttpConstant } from './HttpContent';


const timeout = 20000 // 20s超时
// const baseUrl = 'https://api-harmony-teach.itheima.net/hm/'
const baseUrl = HttpConstant.BaseUrl

export function httpDefaultSetting() {

  // default settings
  axios.defaults.baseURL = baseUrl;
  axios.defaults.timeout = timeout;

  // default headers
  // axios.defaults.headers.common['Client-Type'] = 'xxx';
  axios.defaults.headers.common['Client-Version'] = '1.0.4';
  axios.defaults.headers.common['Os'] = 'hmos';
  // axios.defaults.headers.common['Token'] = 'xxx';

  // for post
  axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

  // 添加请求拦截器
  axios.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    return transRequest(config);
  }, (error: AxiosError) => {
    return Promise.reject(error);
  });

  // 添加响应拦截器
  axios.interceptors.response.use((response: AxiosResponse) => {
    return transResponse(response);
  }, (error: AxiosError) => {
    return Promise.reject(error);
  });
}

/**
 * 请在这里处理请求体的拦截器操作逻辑
 *
 */
function transRequest(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig {
  try {
    let millis = systemDateTime.getTime();
    // config.headers['t'] = millis - Constant.offsetTime; // 同步时间

    // 增加验签逻辑
    // 验签可以仅在需要的请求中增加验签,通过增加特定的header属性来区分
  } finally {
    return config;
  }
}

/**
 * 请在这里处理请求结果的拦截器操作逻辑
 *
 */
function transResponse(response: AxiosResponse): AxiosResponse {
  try {
    let millis = systemDateTime.getTime();
    if (lt != 0 && millis - lt < 60000) {
      return response;
    } // 可选,性能优化 1分钟内避免重复处理
    lt = millis
    // let headers: HashMap<string, ESObject> = JSON.parse(JSON.stringify(response.headers));
    // let t: number = headers['servertimestamp'];
    // Constant.offsetTime = millis - t;
    return response;
  } catch (e) {
    console.error(e)
    return response;
  }
}

let lt = 0

/**
 * Initiates an HTTP request to a given URL.
 *
 * @param url URL for initiating an HTTP request.
 * @param params Params for initiating an HTTP request.
 */
export function httpGet<D>(url: string, params?: ESObject, headers?: ESObject): Promise<D> {
  return new Promise<D>((resolve: Function, reject: Function) => {
    let startTime = systemDateTime.getTime()
    axios.get<ResponseResult, AxiosResponse<ResponseResult>, null>(url, {
      headers: headers,
      // 指定请求超时的毫秒数(0 表示无超时时间)
      timeout: timeout, // 超时
      // `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
      // 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
      // connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间
      params: params,
    })
      .then((response: AxiosResponse<ResponseResult>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()
        Log.info(`httpGet: Success. duration=${duration} url:${response.config.baseURL}${response.config.url}\n
        config=${JSON.stringify(response.config)}\n
        parmar=${JSON.stringify(response.config.params)}\n
        status=${response.status}\n
        headers${JSON.stringify(response.headers)}\n
        data=${JSON.stringify(response.data)}`);
        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.errorCode}`, message: `${response.data.description}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        Log.info(`httpGet: Success. url:${reason.response?.config.baseURL}${reason.response?.config.url}\n`)
        Log.error(JSON.stringify(reason));
        reject(reason)
      })
  });
}


function getRequestFormData(data?: ESObject): string | undefined {
  if (data == undefined) {
    return undefined;
  }
  let sb = new StringBuilder();
  Object.keys(data).forEach((key: string) => {
    sb.append(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
  })
  const formData = sb.build('&');
  Log.info("getRequestFormData: formData=" + formData);
  return formData;
}

function buildPostRequestHeader(isFormUrlencoded: boolean,
  headers?: Record<ESObject, ESObject>): Record<ESObject, ESObject> {
  if (headers != null) {
    headers['Content-Type'] = isFormUrlencoded ? 'application/x-www-form-urlencoded' : 'application/json'
    return headers
  }
  return {
    'Content-Type': isFormUrlencoded ? 'application/x-www-form-urlencoded' : 'application/json',
  }
}

/**
 * Initiates an HTTP request to a given URL.
 *
 * @param url URL for initiating an HTTP request.
 * @param params Params for initiating an HTTP request.
 */
// o: { [s: string]: ESObject }
export function httpPost<D>(url: string, isFormUrlencoded: boolean = true, data?: ESObject, params?: ESObject,
  headers?: ESObject): Promise<D> {
  // Log.info( "httpPost: ");
  return new Promise<D>((resolve: Function, reject: Function) => {
    let startTime = systemDateTime.getTime()


    axios.post(url, isFormUrlencoded ? getRequestFormData(data) : data, {
      headers: buildPostRequestHeader(isFormUrlencoded, headers),

      // 指定请求超时的毫秒数(0 表示无超时时间)
      timeout: timeout, // 超时
      // `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
      // 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
      // connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间

      params: params,
    })
      .then((response: AxiosResponse<ResponseResult>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()

        Log.info(`httpPost: Success. duration=${duration} url:${response.config.baseURL}${response.config.url}\n
        config=${JSON.stringify(response.config)}\n
        status=${response.status}\n
        body=${response.config.data}\n
        headers${JSON.stringify(response.headers)}\n
        data=${JSON.stringify(response.data)}`);

        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.errorCode}`, message: `${response.data.description}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        Log.error(JSON.stringify(reason));
        reject(reason)
      })
  });
}

/**
 * Initiates an HTTP request to a given URL.
 *
 * @param url URL for initiating an HTTP request.
 * @param params Params for initiating an HTTP request.
 */
export function httpRequest<D>(url: string, method?: Method | string, data?: D,
  config?: AxiosRequestConfig<D>): Promise<ResponseResult> {
  // Log.info( "httpRequest: ");
  return new Promise<ResponseResult>((resolve: Function, reject: Function) => {
    let startTime = systemDateTime.getTime()
    axios.request<ResponseResult, AxiosResponse<ResponseResult>, D>({
      url: url,
      method: method,
      baseURL: baseUrl,
      headers: config?.headers,

      // 指定请求超时的毫秒数(0 表示无超时时间)
      timeout: timeout, // 超时

      // `connectTimeout` 指定请求连接服务器超时的毫秒数(0 表示无超时时间)
      // 如果请求连接服务器超过 `connectTimeout` 的时间,请求将被中断
      // connectTimeout: 60000, // 文档和代码不一致,代码中无法设置连接超时时间

      params: config?.params,
      data: data ?? config?.data
    })
      .then((response: AxiosResponse<ResponseResult>) => {
        let duration = (systemDateTime.getTime() - startTime).toString()

        Log.info(`${method}: Success. duration=${duration} url:${response.config.baseURL}${response.config.url}\n
        config=${JSON.stringify(response.config)}\n
        status=${response.status}\n
        headers${JSON.stringify(response.headers)}\n
        body=${response.config.data}\n
        params=${JSON.stringify(response.config.params)}\n
        data=${JSON.stringify(response.data)}`);


        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.errorCode}`, message: `${response.data.description}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        Log.error(JSON.stringify(reason));
        reject(reason)
      })
  });
}

function isSuccess(response: AxiosResponse): boolean {
  return response.status >= 200 && response.status < 300
}

function isResultSuccess(result: ResponseResult): boolean {
  return result.result == "SUCCESS"
}

StringBuilder

/**
 * @Author wdq
 */
export class StringBuilder {
  private value: string[];

  constructor() {
    this.value = [];
  }

  append(str: string | number | undefined | null): StringBuilder {
    this.value.push(String(str));
    return this;
  }

  appendNotNull(str: string | number | undefined | null): StringBuilder {
    if (str != null) {
      this.value.push(String(str));
    }
    return this;
  }

  build(separator?: string): string {
    return this.value.join(separator);
  }
}

ResponseResult

export default class ResponseResult {
  /**
   * Code returned by the network request: success, fail.
   */

  errorCode: number | string | undefined | null;
  description: string | Resource | undefined | null;
  result: string ;
  /**
   * Data returned by the network request.
   */
  data: string | Object | ArrayBuffer | undefined | null;

  constructor() {
    this.errorCode = "0000";
    this.result = '';
    this.data = null;
  }
}

三、使用

1.在EntryAbility的onWindowStageCreate()中进行初始化

httpDefaultSetting()

2.get请求

/**
   * 获取Banner列表
   */
  static getBannerList() {
    return httpGet<BannerListModel>("banner/get",)
  }

3.post请求

static getBannerList() {
    return httpPost<BannerListModel>("banner/post",)
  }```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值