鸿蒙 HarmonyOS—http 四种请求的统一封装-可直接使用

坑点注意事项

1. 关于 expectDataType

在进行HTTP请求时,我们通常会设置 expectDataType 来指定响应参数的类型。然而,有一个坑需要注意:当使用 expectDataType: http.HttpDataType.OBJECT 来指定响应参数为对象类型时,存在一个BUG。如果结果返回异常,项目会直接瘫痪。为了避免这个问题,我们需要先将接收到的值转换为字符串,然后再解析为对象,例如:JSON.parse(res.result as string)。在封装通用请求方法时,需要注意这一点。

2. 定义好接收类型

在封装通用请求方法时,需要定义好接收类型为 Promise 对象,并加上泛型参数 <T>。这样可以使得请求方法返回的结果具有明确的类型,方便后续的处理和类型推断。

3. 处理 get 方法的 extraData

在使用 get 方法进行请求时,需要将 extraData 中的数据拼接到 URL 地址上。这一步需要单独处理,在公共方法里需要注意将extraData从其中提取出来,并拼接到 URL 地址中。

封装通用请求方法的步骤

  1. 创建一个网络请求。

  2. 封装一个通用的请求方法:

    • 使用基底址和传输的 URL 拼接为完整 URL 地址。

    • 对于 get 方法传输的 data 需要拼接在 URL 地址上,而其他方法的 data 则直接传入 extraData 中。

    • 统一设置请求对象 http.HttpRequestOptions 并定义为 config 进行处理。

  3. 发起请求(httpRequest.request(urlStr, config)),将完整的 URL 地址和请求对象作为参数传入request方法中发起请求。

    • 在处理请求结果时,可以利用返回的状态码 res.responseCode 进行判断处理,例如:401 表示 token 不正确,404 表示请求地址不正确。

    • 根据请求的状态码进行进一步的处理。

  4. 在请求完成后,及时销毁请求对象,以释放资源:httpRequest.destroy().

  5. 将封装好的请求方法封装成一个静态的方法类,方便使用者直接调用。可以根据不同的请求方法参数生成四种请求的静态方法,提高代码的可维护性和复用性。

封装的完整代码

import { http } from '@kit.NetworkKit'
// import { TOKEN_KEY } from '../constants'
// import { BASE_URL } from '../constants/url_var'
import { promptAction, router } from '@kit.ArkUI'
// import { ResponsesData } from './request2'
//传输参数token
export const TOKEN_KEY: string = 'token'
//请求网络的基底址
export const BASE_URL: string = 'https://slwl-api.itheima.net/'
// 最外层数据封装类的
export class ResponsesData<T> {
  code: number = 0
  msg: string = ""
  data: T | null = null
}
interface EmptyInterface {}


//Next版本不支持在箭头函数上写纯泛型,
// function requestHttp(url: url地址, method: 请求方法类型,默认为get, data?: 参数类型) : 返回类型是: Promise里面的T类型的数据
async function requestHttp<T>(url: string = '', method: http.RequestMethod = http.RequestMethod.GET, data?: object): Promise<T> {
  //创建一个网络请求
  const httpRequest = http.createHttp()
  //拼接地址
  let urlStr = BASE_URL + url
  //get方法需要自己拼接
  if (method = http.RequestMethod.GET) {
    //如果data里面有值并且里面有对象的时候
    if (data && Object.keys(data).length) {
      urlStr += "?" + Object.keys(data).map(key => {
        if (data[key]) {
          return `${key}=${data[key]}` // a=1 =>
        }
        return ""
      }).join('&') //['a=1','b=2','c=3']
    }
  }
  //设置请求对象
  let config: http.HttpRequestOptions = {
    //method同名方法赋值,参数名和属性名相同时只需要写一个method等价于method:method
    method,
    //超时时间
    readTimeout: 10000,
    //get的extraData参数在上面处理过了 在这儿不需要再传一遍
    extraData: method === http.RequestMethod.GET ? '' : data || {} as EmptyInterface,
    //响应参数的类型,指定为对象后有BUG,当结果有问题时,项目会直接瘫痪
    // expectDataType: http.HttpDataType.OBJECT,
    //请求头
    header: {
      'Content-Type': 'application/json',
      "Authorization": AppStorage.get(TOKEN_KEY) as string || ''
    }
  }
  //发请求
  try {

    const res = await httpRequest.request(urlStr, config)
    console.log('请求url地址', urlStr)
    //res.responseCode响应状态码,这里的401还会认为是请求成功
    if (res.responseCode === 401) {
      //401 token超时
      //删除持久化数据token
      AppStorage.set<string>(TOKEN_KEY, '')
      promptAction.showToast({ message: 'token超时!' })
      //回登录
      router.replaceUrl({
        url: 'pages/Login/LoginPage'
      })
      //返回错误 终止
      return Promise.reject(new Error('token超时!'))
    } else if (res.responseCode === 404) {
      promptAction.showToast({ message: '请求地址不正确!' })
      return Promise.reject(new Error('请求地址不正确!'))
    } else {
      //指定为字符串,然后再转成一个对象,类型是不明确的要使用泛型,返回第一层+泛型,泛型的定义是一个类和之前的有所差距
      const result = JSON.parse(res.result as string) as ResponsesData<T>
      //再判断返回的状态码进行处理,不是200都是失败
      if (result.code === 200) {
        return result.data as T
      } else {
        promptAction.showToast({ message: '服务器异常!' })
        return Promise.reject(new Error(result.msg))
      }
    }
  } catch (error) {
    promptAction.showToast({ message: error })
    return Promise.reject(error)
  }
  //执行最后销毁请求
  finally {
    //销毁请求请求结束
    httpRequest.destroy()
  }
}

//封装一个静态类的方法出来使用
export class Request {
  static get<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.GET, data)
  }

  static post<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.POST, data)
  }

  static put<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.PUT, data)
  }

  static delete<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.DELETE, data)
  }
}

  • 19
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值