HarmonyOS鸿蒙应用开发——HTTP网络访问与封装

文章目录

    • 网络基础
    • 基本使用
    • 封装
    • 参考

网络基础

  • 网络基础-TCPIP协议分层模型
  • TCP协议-三次握手与四次挥手
  • UDP协议-简单高效的传输协议
  • HTTP协议-应用间的通信协议

基本使用

鸿蒙应用发起HTTP请求的基本使用,如下:

  • 导入http模块
  • 创建httpRequest对象
  • 发起http请求,并处理响应结果

第一、导入http模块:

import http from '@ohos.net.http'

第二、创建httpRequest对象,注意的是每一个httpRequest对象对应一个http请求任务,不可复用。

 const httpRequest = http.createHttp()

第三、发起请求,比如POST请求

 httpRequest.request(
  // 请求url地址
  url,
  {
    // 请求方式
    method: http.RequestMethod.POST,
    // 请求的额外数据。
    extraData: {
      "param1": "value1",
      "param2": "value2",
    },
    // 可选,默认为60s
    connectTimeout: 60000,
    // 可选,默认为60s
    readTimeout: 60000,
    // 开发者根据自身业务需要添加header字段
    header: {
      'Content-Type': 'application/json'
    }
  })
  .then((data) => { 
  if (data.responseCode === http.ResponseCode.OK) {
  	// 处理响应结果
  	// data.result为服务器返回的业务数据
    console.info('Result:' + data.result);
    console.info('code:' + data.responseCode);
  }
}).catch((err) => {
 console.info('error:' + JSON.stringify(err));
});

最后需要声明网络权限,在module.josn5文件中声明:

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

上面就是网络请求的简单使用,接下来通过Promise来封装一个网络请求库,统一管理请求参数、响应数据、日志的输出等,对外屏蔽了细节,使用者只需定义业务数据的实体类以及调用即可。

封装

以**玩Android**开放接口为测试用例

定义业务数据的实体类,通过泛型来接收不同的数据类型:

export class ResponseResult<T> {
  errorCode: number;
  errorMsg: string;
  data?: T | Object | string;
}

把各种请求方式用枚举声明RequestMethod

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

其实在http模块中已经有对应的枚举,之所以再用一个新枚举来声明,是简化使用,同时也是将http模块相关细节屏蔽掉不对外开放,这样就可以灵活替换网络库,也具有扩展性。

定义一个HttpUtils类实现:

export class HttpUtils{
  public static readonly SUCCESS_CODE: number = 0
  public static readonly READ_TIME_OUT = 60 * 1000
  public static readonly CONNECT_TIME_OUT = 60 * 1000
  private baseUrl: string = ""

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl
  }

  private methodName(method: RequestMethod): http.RequestMethod {
    switch (method){
      case RequestMethod.OPTIONS:{
        return http.RequestMethod.OPTIONS
      }
      case RequestMethod.GET:{
        return http.RequestMethod.GET
      }
      case RequestMethod.HEAD:{
        return http.RequestMethod.HEAD
      }
      case RequestMethod.POST:{
        return http.RequestMethod.POST
      }
      case RequestMethod.PUT:{
        return http.RequestMethod.PUT
      }
      case RequestMethod.DELETE:{
        return http.RequestMethod.DELETE
      }
      case RequestMethod.TRACE:{
        return http.RequestMethod.TRACE
      }
      case RequestMethod.CONNECT:{
        return http.RequestMethod.CONNECT
      }

    }

  }

  private tag(n: string): string {
    return `${TAG}/${n}`
  }

  request<T>(path: string, reqMethod: RequestMethod, parameter: Map<string, Object> = null): Promise<T | null> {
    // 注意的是每一个httpRequest对象对应一个http请求任务,不可复用。
    const httpRequest = http.createHttp()
    const method = this.methodName(reqMethod)
    let extraData = {}
    let url = `${this.baseUrl}/${path}`
    if (parameter != null) {
      switch (reqMethod) {
        case RequestMethod.POST, RequestMethod.PUT: {
          extraData = Object.fromEntries(parameter)
          break;
        }
        case RequestMethod.GET,RequestMethod.DELETE: {
          const urlParams = Object.keys(parameter).map(key => `${key}=${parameter[key]}`).join('&')
          if (url.includes("?")) {
            url = `${url}${urlParams}`
          } else {
            url = `${url}?${urlParams}`
          }
          break;
        }
      }
    }
    let n = Math.random().toString(10).slice(2)
    LogUtils.debug(this.tag(n), "==================Request====================")
    LogUtils.debug(this.tag(n), "url: " + url)
    LogUtils.debug(this.tag(n), "method: " + method.toString())
    if (reqMethod == RequestMethod.POST || reqMethod == RequestMethod.PUT)
      LogUtils.debug(this.tag(n), "extraData: " + JSON.stringify(parameter, null, 2))

    return new Promise( async (resolve, reject) => {
      let beginTime = await systemDateTime.getCurrentTime(false)
      httpRequest.request(url,
        {
          method,
          readTimeout: HttpUtils.READ_TIME_OUT,
          connectTimeout: HttpUtils.CONNECT_TIME_OUT,
          header: {
            'Content-Type': 'application/json'
          },
          extraData
        }
      ).then( async (value) => {
        let endTime = await systemDateTime.getCurrentTime(false)
        LogUtils.debug(this.tag(n), "==================Response====================")
        LogUtils.debug(this.tag(n), "url: " + url + " "+ (endTime - beginTime)+"ms")
        LogUtils.debug(this.tag(n), "method: " + method.toString())
        LogUtils.debug(this.tag(n), "header: " + JSON.stringify(value.header, null, 2))
        LogUtils.debug(this.tag(n), "responseCode: " + value.responseCode)
        LogUtils.debug(this.tag(n), "resultType: " + value.resultType)
        if (value.responseCode == http.ResponseCode.OK) {
          let result: ResponseResult<T> = JSON.parse(value.result.toString())
          LogUtils.debug(this.tag(n), "body: " + JSON.stringify(result, null, 2))
          if (result.errorCode == HttpUtils.SUCCESS_CODE) {
            resolve(result.data as T)
          } else {
            reject(result.errorMsg)
          }
        } else {
          reject("请求失败")
        }
      }).catch((reason) => {
        reject(reason)
      })
    })
  }

  get<T>(path: string, parameter: Map<string, Object> = null): Promise<T | null> {
    return this.request<T>(path, RequestMethod.GET, parameter)
  }

  post<T>(path: string, parameter: Map<string, Object> = null): Promise<T | null> {
    return this.request<T>(path, RequestMethod.POST, parameter)
  }

  delete<T>(path: string, parameter: Map<string, Object> = null): Promise<T | null> {
    return this.request<T>(path, RequestMethod.DELETE, parameter)
  }

  put<T>(path: string, parameter: Map<string, Object> = null): Promise<T | null> {
    return this.request<T>(path, RequestMethod.PUT, parameter)
  }

}
const YiNet = new HttpUtils(BASE_URL)
export default YiNet

使用发起网络请求:

  aboutToAppear() {
    let map = new Map<string,string>()
    map["cid"] = 294
    YiNet.get<ArticleList>("project/list/1/json",map).then((data)=>{
      this.data = JSON.stringify(data, null, 2)
    })

    let map2 = new Map<string,string>()
    map2["username"] = "123"
    map2["password"] = "123456"
    YiNet.post<User>("user/login",map2).then((data)=>{
      this.data = JSON.stringify(data, null, 2)
    }).catch((err)=>{
      Prompt.showToast({message:err})
    })
  }

日志输出效果:

HarmonyOS鸿蒙应用开发——HTTP网络访问与封装_第1张图片
如果有多个请求,日志可能会混合交叉不利于查看,可以通过HttpUtils/xxxxxx来查看具体某一个请求日志,其中xxxx是一个随机数大部分情况下是具有唯一性。

上面就是官方的http模块的基本封装,在此基础上可以设计一套拦截器来辅助业务需求。

参考

  • https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101667364948559963?ha_linker=eyJ0cyI6MTcwMjE3NzI3OTYyMywiaWQiOiI4MmM3ZTI1MmFmMDJlMDZiODBmOGU1ZDM5ZTI5YmMyOCJ9
  • https://www.wanandroid.com/blog/show/2

你可能感兴趣的:(HarmonyOS应用开发,harmonyos,http,华为,网络封装,鸿蒙,udp,tcp)