HarmonyOS Next开发,使用Promise异步回调方式封装http请求

目录

前言

版本说明:本文的API版本为12

一、业务场景

1、登录注册功能

2、商品详情页功能

二、封装http请求

1、创建resultVO接口

2、创建requestParams接口

3、创建request文件,封装http请求

3.1  编写request方法

3.2  返回Promise对象前,先获取一下关键参数

3.3  发送request请求

3.4  根据业务需要处理请求后的逻辑

例1:拦截token过期

例2:处理正确状态码

三、完整文件代码

文件1:常量类

文件2:resultVO接口

文件3:requestParams接口

文件4:request文件

四、发送request请求 

1、开启网络权限

2、测试登录请求

2.1  创建LoginDTO接口

2.2  测试

2.3  结果

附录


前言

        本专栏记录鸿蒙应用开发的一些知识,供鸿蒙开发者学习。笔者目前还是个小菜鸡,鸿蒙开发也是我看相关资料自学的,所以本文有些地方可能考虑不够周到,有些纰漏,就当抛砖引玉,还望读者海涵。目前HarmonyOS Next已经发布,API已更新至12,只有鸿蒙的开发者越来越多,才能更好的去改进HarmonyOS,去做好我们国人自己的系统,防止被别人卡脖子。本专栏适合初学者做一个入门,同时默认读者具备一定前端基础。本专栏的内容可以做一些课设,毕设之类的。但对于企业中的真实需求,可能考虑不够周到。因为笔者目前还没有工作(T_T)


         本文主要讲解HarmonyOS Next开发http请求的封装。发送http请求需要申请ohos.permission.INTERNET权限。官方文档地址:http请求


版本说明:本文的API版本为12


一、业务场景

1、登录注册功能

        在APP的登录注册功能中,我们往往需要访问后台数据库。用户登录时,输入账号和密码,点击登陆后,前端发起登录请求。后端接收到请求后,处理对应的逻辑,判断用户是否注册,密码是否正确等。

2、商品详情页功能

        商品详情页功能,当我们点开某一个商品项的时候,前端将该商品的ID发送给后端,后端响应对应的商品详情信息给前端,前端再将数据进行一个渲染。

二、封装http请求

        官方文档里的http开发指南比较全面,如果我们是做课设,或者是毕设,有些东西可以省去。下面我来讲解主要的步骤。

1、创建resultVO接口

        前端发送请求后,后端返回的数据一般是如下格式:code--响应状态码;msg--响应信息;data--响应数据。响应数据data一般有多种类型,这里用泛型T接收,外部调用时,再指定T的类型。ArkTS是TypeScipt的超集,一般TS有的,ArkTS也有。所以ArkTS也支持泛型。

/*
  * resultVO接口
  * @code 响应码
  * @msg  响应信息
  * @data 响应数据
 */
export default interface resultVO<T>{
  code: number
  msg: string
  data: T
}

2、创建requestParams接口

        此接口用于规范调用http请求时的参数。

import { http } from '@kit.NetworkKit'

/*
  * requestParams接口
  * @url          必填                     访问地址  (后端api访问地址)
  * @method       选填(默认get)           请求方法  (get、post...)
  * @extraData    选填(默认undefined )    请求参数
 */
export interface requestParams{

  url: string
  method?: http.RequestMethod
  extraData?: object

}

3、创建request文件,封装http请求

3.1  编写request方法

        request方法需传入请求参数(requestParams接口),并返回一个Promise对象,该对象里面是resultVO<T>类型的数据。

/*
  * request方法
  * @params requestParams接口类型
  * @@return Promise<resultVO<T>>
 */
export const request = async <T>(params: requestParams): Promise<resultVO<T>> => {
  
  /*
    * @resolve 请求成功
    * @reject  请求失败
   */
  return new Promise(async (resolve, reject) => {
    

  })

}

3.2  返回Promise对象前,先获取一下关键参数

        如果是本地模拟器访问本地的SpringBoot服务器,基地址为你所使用的电脑,它的IPv4地址。移动端项目和Vue项目不同,Vue项目的基地址一般是127.0.0.1,这个需要注意。我们这里把基地址设置成一个常量。要修改是,去常量类里面修改,提高代码的维护性。

        token可以使用首选项进行存储和调用。首选项的知识可以看我的另外一篇文章:封装用户首选项

        请求头一般是json类型,如有其他需求,可以更改。这个一般是和后端协调决定。如果自己做课设或者毕设,这里传一个token进来就可以了。

  // 基地址。如果用本地模拟器访问,基地址一般为 “http://本机的IPv4地址:8080”
  const baseURL: string = CommonConstants.BASE_URL

  // 创建一个HttpRequest对象 -- 不可复用,一个httpRequest对象对应一个http请求
  let httpRequest = http.createHttp()

  // 获取token
  let token: preferences.ValueType = await PreferenceUtil.getPreferenceValue(
    CommonConstants.TOKEN, CommonConstants.NULL_TOKEN
  )

  // 完整请求地址
  let requestUrl = baseURL + params.url

  // 发起请求可选参数的类型和取值范围。
  let options: http.HttpRequestOptions = {

    // 请求类型,不传默认get
    method: params.method ?? http.RequestMethod.GET,

    // 请求头
    // 做课设、毕设之类的,'Content-Type'默认'application/json'就好
    // 请求头只用携带一个token,用于身份的校验
    header: {
      'Content-Type': 'application/json',
      token
    },

    // 请求参数,不传默认undefined
    extraData: params.extraData ?? undefined,

    // 必填,不知道是不是bug,不填object类型,就会拿不到后端数据,和官方文档不一样
    // 也可能是我后端接口的问题。----------这里存疑----------
    expectDataType: http.HttpDataType.OBJECT
  }

3.3  发送request请求

        获取所需的参数之后,我们就可以发起request请求了,具体如下。请求成功后,记得销毁httpRequest对象,释放内存。

  /*
    * @resolve 请求成功
    * @reject  请求失败
   */
  return new Promise(async (resolve, reject) => {

    /*
      * 发送http请求
      * @url          后端api完整地址
      * @options      发起请求的可选参数
      * @callback     回调函数
     */
    httpRequest.request(

      requestUrl,

      options,

      (err, data) => {

        if (!err) {

          // 处理请求成功的逻辑

          // 获得后端返回过来的resultVO
          const res = data.result as resultVO<T>

        } else {

          // 处理请求失败的逻辑

          promptAction.showToast({message: CommonConstants.REQUEST_ERROR})

          console.error('error:' + JSON.stringify(err))
          reject(err)

        }

        // 销毁httpRequest对象
        httpRequest.destroy()
      }

    )

  })

3.4  根据业务需要处理请求后的逻辑

例1:拦截token过期
          // token过期
          if(res.code == CommonConstants.TOKEN_INVALIDATION){

            promptAction.showToast({message: CommonConstants.TOKEN_INVALIDATION_MSG})

            //清空历史页面
            router.clear()
            //跳转到登录页
            router.replaceUrl({
              url: CommonConstants.LOGIN_PAGE_URL
            })

            return
          }
例2:处理正确状态码
          // 判断响应码
          if(res.code == CommonConstants.CODE_SUCCESS){

            // 返回想要的的结果
            resolve(res)

          }else {

            promptAction.showToast({message: res.msg})
            return
          }

三、完整文件代码

文件1:常量类

export class CommonConstants {
  
  static readonly BASE_URL: string = 'http://192.168.31.160:8080'

  // global data key
  static readonly G_STORE: string = 'GreenTreasureStore';

  static readonly TOKEN: string = 'TOKEN'

  static readonly NULL_TOKEN: string = null

  static readonly TOKEN_INVALIDATION : number = 401

  static readonly CODE_SUCCESS : number = 1

  static readonly TOKEN_INVALIDATION_MSG : string = 'token过期,请重新登录'

  static readonly REQUEST_ERROR : string = '请求失败'

  static readonly LOGIN_PAGE_URL : string = '/pages/Login/Index'

}

文件2:resultVO接口

/*
  * resultVO接口
  * @code 响应码
  * @msg  响应信息
  * @data 响应数据
 */
export default interface resultVO<T>{
  code: number
  msg: string
  data: T
}

文件3:requestParams接口

import { http } from '@kit.NetworkKit'

/*
  * requestParams接口
  * @url          必填                     访问地址  (后端api访问地址)
  * @method       选填(默认get)           请求方法  (get、post...)
  * @extraData    选填(默认undefined )    请求参数
 */
export interface requestParams{

  url: string
  method?: http.RequestMethod
  extraData?: object

}

文件4:request文件

import { http } from '@kit.NetworkKit'
import { preferences } from '@kit.ArkData'
import PreferenceUtil from '../utils/PreferencesUtil'
import resultVO from '../common/impl/resultVO'
import { CommonConstants } from '../constants/CommonConstants'
import { requestParams } from '../common/impl/requestParams'
import { promptAction, router } from '@kit.ArkUI'

/*
  * request方法
  * @params requestParams接口类型
  * @@return Promise<resultVO<T>>
 */
export const request = async <T>(params: requestParams): Promise<resultVO<T>> => {

  // 基地址。如果用本地模拟器访问,基地址一般为 “http://本机的IPv4地址:8080”
  const baseURL: string = CommonConstants.BASE_URL

  // 创建一个HttpRequest对象 -- 不可复用,一个httpRequest对象对应一个http请求
  let httpRequest = http.createHttp()

  // 获取token
  let token: preferences.ValueType = await PreferenceUtil.getPreferenceValue(
    CommonConstants.TOKEN, CommonConstants.NULL_TOKEN
  )

  // 完整请求地址
  let requestUrl = baseURL + params.url

  // 发起请求可选参数的类型和取值范围。
  let options: http.HttpRequestOptions = {

    // 请求类型,不传默认get
    method: params.method ?? http.RequestMethod.GET,

    // 请求头
    // 做课设、毕设之类的,'Content-Type'默认'application/json'就好
    // 请求头只用携带一个token,用于身份的校验
    header: {
      'Content-Type': 'application/json',
      token
    },

    // 请求参数,不传默认undefined
    extraData: params.extraData ?? undefined,

    // 必填,不知道是不是bug,不填object类型,就会拿不到后端数据,和官方文档不一样
    // 也可能是我后端接口的问题。----------这里存疑----------
    expectDataType: http.HttpDataType.OBJECT
  }

  /*
    * @resolve 请求成功
    * @reject  请求失败
   */
  return new Promise(async (resolve, reject) => {

    /*
      * 发送http请求
      * @url          后端api完整地址
      * @options      发起请求的可选参数
      * @callback     回调函数
     */
    httpRequest.request(

      requestUrl,
      options,
      (err, data) => {

        if (!err) {

          // 处理请求成功的逻辑

          console.info('httpRequest','code:' + JSON.stringify(data.result['code']))
          console.info('httpRequest','msg:' + JSON.stringify(data.result['msg']))
          console.info('httpRequest','data:' + JSON.stringify(data.result['data']))

          // 获得后端返回过来的resultVO
          const res = data.result as resultVO<T>

          // token过期
          if(res.code == CommonConstants.TOKEN_INVALIDATION){

            promptAction.showToast({message: CommonConstants.TOKEN_INVALIDATION_MSG})

            //清空历史页面
            router.clear()
            //跳转到登录页
            router.replaceUrl({
              url: CommonConstants.LOGIN_PAGE_URL
            })

            return
          }

          // 判断响应码
          if(res.code == CommonConstants.CODE_SUCCESS){

            // 返回想要的的结果
            resolve(res)

          }else {
            
            promptAction.showToast({message: res.msg})
            return
          }

        } else {

          // 处理请求失败的逻辑

          promptAction.showToast({message: CommonConstants.REQUEST_ERROR})

          console.error('error:' + JSON.stringify(err))
          reject(err)

        }

        // 销毁httpRequest对象
        httpRequest.destroy()

      }
    )
  })
}

四、发送request请求 

1、开启网络权限

        想要发送http请求,必须开启网络权限。网络权限开启步骤如下:

        1.1  找到文件entry/src/main/module.json5

        1.2 进入文件module.json5,在【module】的下一级,加上:

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

2、测试登录请求

        可以自己找一些后端接口进行测试。这里是笔者自己写的后端接口。后端接口的编写本文暂时不讲。读者可以自己试着写写看。

2.1  创建LoginDTO接口

        该接口规范登录请求的参数

export interface  LoginDTO{

  userPhone: string
  password: string

}

2.2  测试

import { LoginDTO } from '../common/dto/LoginDTO'
import { request } from '../utils/request';
import { http } from '@kit.NetworkKit';

const login = (loginDto: LoginDTO) => {
  return request<string>({
    url: `/user/api/login?userPhone=${loginDto.userPhone}&password=${loginDto.password}`,
    method: http.RequestMethod.POST,
  })
}

@Entry
@Component
struct Index {

  async aboutToAppear() {

    const res = await login({userPhone: '13652576888',password:'123456'})
  }

  build() {
  }
}

2.3  结果

附录

参考文章:https://blog.csdn.net/sd1sd2/article/details/139536268

        文章结束,如有纰漏还望指正。可以在评论区留下自己的想法。思想的碰撞是自我提升的催化剂,可以激发创新和进步。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值