HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装

发布于 1周前 作者 gougou168 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装

基于 axios 和 Promise 的网络框架封装 DevEco Studio 版本:DevEco Studio NEXT

HarmonyOS API 版本:5.0.0(12)

axios 版本:2.2.0

Get Post 方式支持 http 其他请求方式(method)支持 接口 url 参数封装 和 全局的 baseUrl 设置 超时时间设置 全局 Headers,接口自定义 Headers 和 请求 headers 拦截器封装和实现 请求 params 参数和 data 数据支持 post 支持 x-www-form-urlencoded 数据格式 请求结果 Json 数据解析(框架已自动解析) 请求结果流程控制,Promise 封装 请求结果 header 数据解析,服务器时间戳和 session 关键代码 HttpUtil.ets封装如下:

import axios, { AxiosError, AxiosResponse } from "@ohos/axios";
import {ResponseModel} from "../model/ResponseModel"
import { ConfigUtil as Config } from "./ConfigUtil";
// axios.defaults.baseURL = 'https://xiaomi.itying.com';
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.timeout=5000; //超时间是5秒

export function HttpGet(apiUri:string):Promise<ResponseModel>{
  let responseData: ResponseModel=new ResponseModel();
  return axios.get(apiUri).then((response:AxiosResponse)=>{
    responseData.success=true;
    responseData.message=Config.HTTP_GET_SUCCESS;
    responseData.result=response.data["result"];
    return responseData;
  }).catch((err:AxiosError)=>{
    responseData.success=false;
    responseData.message="Error:"+JSON.stringify(err);
    responseData.result=[];
    return responseData;
  })
}
export function HttpPost<T>(apiUri:string,extraData:T):Promise<ResponseModel>{
  let responseData: ResponseModel=new ResponseModel();
  return axios.post<object,AxiosResponse,T>(apiUri,extraData).then((response:AxiosResponse)=>{
    responseData.success=true;
    responseData.message=Config.HTTP_POST_SUCCESS;
    responseData.result=response.data["result"];
    return responseData;
  }).catch((err:AxiosError)=>{
    responseData.success=false;
    responseData.message="Error:"+JSON.stringify(err);
    responseData.result=[];
    return responseData;
  })

}

export function HttpPut<T>(apiUri:string,extraData:T):Promise<ResponseModel>{
  let responseData: ResponseModel=new ResponseModel();
  return axios.put<object,AxiosResponse,T>(apiUri,extraData).then((response:AxiosResponse)=>{
    responseData.success=true;
    responseData.message=Config.HTTP_PUT_SUCCESS;
    responseData.result=response.data["result"];
    return responseData;
  }).catch((err:AxiosError)=>{
    responseData.success=false;
    responseData.message="Error:"+JSON.stringify(err);
    responseData.result=[];
    return responseData;
  })
}

export function HttpDelete(apiUri:string):Promise<ResponseModel>{
  let responseData: ResponseModel=new ResponseModel();
  return axios.delete(apiUri).then((response:AxiosResponse)=>{
    responseData.success=true;
    responseData.message=Config.HTTP_DELETE_SUCCESS;
    responseData.result=response.data["result"];
    return responseData;
  }).catch((err:AxiosError)=>{
    responseData.success=false;
    responseData.message="Error:"+JSON.stringify(err);
    responseData.result=[];
    return responseData;
  })
}

export function ReplaceUri(str: string) {
  // public\upload\zon0TTXnXUs1z5meqZhP5aNF.png
  //public/upload/zon0TTXnXUs1z5meqZhP5aNF.png
  try {
    return str.split("\\").join("/")
  }catch{
    return str
  }
}

关于HarmonyOS 鸿蒙Next基于axios和Promise的网络框架封装的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

14 回复

案例怎么用的呀?

基于楼主HarmonyOS 鸿蒙Next封装的axios的用法

import { ConfigUtil as Config } from '../common/ConfigUtil'
import { HttpDelete, HttpGet, HttpPost, HttpPut } from '../common/HttpUtil'
import { ResponseModel } from '../model/ResponseModel'
import { UserInfoInterface, UserModel } from '../model/UserModel'

@Entry
@Component
export struct Index {
  aboutToAppear() {

  }
  //Get 获取数据
  getData() {
    let apiUri:string=`${Config.SERVER}/httpGet?username=aaaa&age=20`
    HttpGet(apiUri).then((response:ResponseModel)=>{
      console.log("HttpGet...");
      console.log(JSON.stringify(response));
    })
  }
  //Post用于提交数据
  postData() {
    let apiUri:string= `${Config.SERVER}/api/httpPost`;
    HttpPost<UserInfoInterface>(apiUri,{
      username:"张三",
      address:"北京市",
    }).then((response:ResponseModel)=>{
      console.log("HttpPost...");
      console.log(JSON.stringify(response));
    })

  }
  //Put用于修改数据
  putData() {
    let apiUri:string=`${Config.SERVER}/api/httpPut`;
    HttpPut<UserModel>(apiUri,{
      id:123,
      username:"李四",
      address:"哈哈哈"
    }).then((response:ResponseModel)=>{
      console.log("HttpPut...");
      console.log(JSON.stringify(response));
    })
  }
  //Delete用于删除数据
  deleteData() {
    let apiUri:string=`${Config.SERVER}/api/httpDelete`;
    HttpDelete(apiUri).then((response:ResponseModel)=>{
      console.log("HttpDelete...");
      console.log(JSON.stringify(response));
    })
  }

  build() {
    Column() {
      Button() {
        Text("Get请求").fontSize(16).fontColor(Color.White)
      }
      .width('80%')
      .height(50)
      .margin({ top: 20 })
      .onClick(() => {
        this.getData()
      })

      Button() {
        Text("Post请求").fontSize(16).fontColor(Color.White)
      }
      .width('80%')
      .height(50)
      .margin({ top: 20 })
      .onClick(() => {
        this.postData()
      })

      Button() {
        Text("Put请求").fontSize(16).fontColor(Color.White)
      }
      .width('80%')
      .height(50)
      .margin({ top: 20 })
      .onClick(() => {
        this.putData()
      })

      Button() {
        Text("Delete请求").fontSize(16).fontColor(Color.White)
      }
      .width('80%')
      .height(50)
      .margin({ top: 20 })
      .onClick(() => {
        this.deleteData()
      })

    }.height('100%')
    .justifyContent(FlexAlign.Center)
    .width("100%")
  }
}

期待HarmonyOS能在未来推出更多针对特定场景的优化功能。

我也封装了一个,不过楼主的更好一些

 
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, Method } from '@ohos/axios';

import ResponseResult from './ResponseResult';
import logger from '../util/Logger';
import { systemDateTime } from '@kit.BasicServicesKit';
import { HashMap } from '@kit.ArkTS';
import Constant from '../common/Constant';

const TAG: string = "HttpUtil"

const timeout = 20000 // 20s超时
const baseUrl = 'https://xxx.xxx.com'

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> {
  logger.debug(TAG, "httpGet: ");
  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()
        logger.debug(TAG, "httpGet: Success. duration=" + duration);
        logger.debug(TAG, "--------------------------------------");
        logger.debug(TAG, "config=" + JSON.stringify(response.config));
        logger.debug(TAG, "status=" + response.status);
        // logger.debug(TAG, "statusText=" + response.statusText); // always empty??
        logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
        logger.debug(TAG, "data=" + JSON.stringify(response.data));
        logger.debug(TAG, "--------------------------------------");
        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        logger.error(TAG, 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('&');
  logger.debug(TAG, "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> {
  // logger.debug(TAG, "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()
        logger.debug(TAG, "httpPost: Success. duration=" + duration);
        logger.debug(TAG, "--------------------------------------");
        logger.debug(TAG, "config=" + JSON.stringify(response.config));
        logger.debug(TAG, "status=" + response.status);
        // logger.debug(TAG, "statusText=" + response.statusText); // always empty??
        logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
        logger.debug(TAG, "data=" + JSON.stringify(response.data));
        logger.debug(TAG, "--------------------------------------");
        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        logger.error(TAG, 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> {
  // logger.debug(TAG, "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()
        logger.debug(TAG, "httpRequest: Success. duration=" + duration);
        logger.debug(TAG, "--------------------------------------");
        logger.debug(TAG, "config=" + JSON.stringify(response.config));
        logger.debug(TAG, "status=" + response.status);
        // logger.debug(TAG, "statusText=" + response.statusText); // always empty??
        logger.debug(TAG, "headers=" + JSON.stringify(response.headers));
        logger.debug(TAG, "data=" + JSON.stringify(response.data));
        logger.debug(TAG, "--------------------------------------");
        if (isSuccess(response)) {
          if (isResultSuccess(response.data)) {
            resolve(response.data.data);
          } else {
            const e: Error = { name: `${response.data.code}`, message: `${response.data.msg}` }
            reject(e);
          }
        } else {
          const e: Error = { name: `${response.status}`, message: `${response.statusText}` }
          reject(e);
        }
      })
      .catch((reason: AxiosError) => {
        logger.error(TAG, JSON.stringify(reason));
        reject(reason)
      })
  });
}

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

function isResultSuccess(result: ResponseResult): boolean {
  return result.code == 0
}

StringBuilder是类似Java的字符串拼接类么?求共享,好像arkts没有啥好的拼接字符的工具类。

是的,自己封装的一个工具类,代码如下:

/**

  • @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); } }

axios.request时,设置method为post,请求时好像并不是post请求

暂时没遇到过,或者你代码发出来看看

老铁可以把你写的这块代码发我一份吗

主要的代码全部都有了,参考着写就行了

httpDefaultSetting这个方法在什么时候使用啊

初始化设置一些默认值,一般在 EntryAbility 的 oncreate 调用即可

offsetTime 是什么?一般设置多少?

我这里的offsetTime指的是跟服务端的时间差,同步时间用的,逻辑是通过拿接口中服务端在header中的时间戳,跟本地时间戳的差值。具体参考上面的代码。

回到顶部