文章介绍的是HarmonyOS中原生http请求工具的封装,并基于工具定义get/post/put/delete请求方法。

首先,我们先创建基地址和一个function函数并给函数三个形参,分别是url(请求的接口地址),method(请求的类型),data(请求传的参数。

其中data不是什么时候都需要传的,所以将data设为可选。

const BASE_URL = 'https://.....'  // 请求基础地址
// T为泛型,用来定义响应类型
async function requestHttp<T>(url: string = "", method: http.RequestMethod, data?: object): Promise<T> {
    
}

创建请求对象,根据基地址拼接请求地址

  const BASE_URL = 'https://.....'  // 请求基础地址
// T为泛型,用来定义响应类型
async function requestHttp<T>(url: string = "", method: http.RequestMethod, data?: object): Promise<T> {
  // http需要创建一个请求对象
  const httpRequest = http.createHttp() 
  let urlStr = BASE_URL + url // 基础地址拼接url地址
}

我们先处理get请求,当使用get请求时,将请求的参数拼接到地址上。

  const BASE_URL = 'https://.....'  // 请求基础地址
// T为泛型,用来定义响应类型
async function requestHttp<T>(url: string = "", method: http.RequestMethod, data?: object): Promise<T> {
  // http需要创建一个请求对象
  const httpRequest = http.createHttp()
  let urlStr = BASE_URL + url // 基础地址拼接url地址
  //判断是不是get请求
    if (method === http.RequestMethod.GET) {
        //如果是get请求,判断有没有传请求参数
    if (data && Object.keys(data).length) {
      // 如果有请求参数则拼接到地址上 data参数都拼接到地址上  ?a=1&b=2&c=3
      //filter 过滤掉为空的参数 避免出现错误
      urlStr += "?" + Object.keys(data).filter(key =>
      !!data[key]).map(key => {
        return `${key}=${data[key]}`
      }).join("&")
    }
  }
}

get请求处理的差不多了,接下来是其它请求,先组装一下参数,比如给请求头添加token(token存储详见axios请求工具封装)

  const BASE_URL = 'https://.....'  // 请求基础地址
// T为泛型,用来定义响应类型
async function requestHttp<T>(url: string = "", method: http.RequestMethod, data?: object): Promise<T> {
  // http需要创建一个请求对象
  const httpRequest = http.createHttp() 
  let urlStr = BASE_URL + url // 基础地址拼接url地址
  //判断是不是get请求
    if (method === http.RequestMethod.GET) {
        //如果是get请求,判断有没有传请求参数
    if (data && Object.keys(data).length) {
      // 如果有请求参数则拼接到地址上 data参数都拼接到地址上  ?a=1&b=2&c=3
      //filter 过滤掉为空的参数 避免出现错误
      urlStr += "?" + Object.keys(data).filter(key =>
      !!data[key]).map(key => {
        return `${key}=${data[key]}`
      }).join("&")
    }
  }
      // 组装参数
  const config: http.HttpRequestOptions = {
    extraData: method !== http.RequestMethod.GET ? data : "", // 当请求类型不等于get时 
    header: {
      Authorization: AppStorage.get(TOKEN_KEY) || "", // 设置请求头的token
    },
    method,// method 是通过形参传进来的请求类型
    readTimeout: 20000 // 如果多少秒没响应就断开
  }
    
}

接下来就是发请求了,同时处理一下错误信息,比如token失效,跳转到登录页(现在只写部分代码,结尾会放上完整代码)。

我们先了解一下常见的错误码代表的是什么意思

200 请求成功, 2开头的异步表示请求成功

304 请求被允许,但请求内容没有改变, 3开头的一般请求完成

4xx开头状态码=>客户端错误

400 => 传参格式不正确

​ 401 => 权限认证未通过

​ 403 => 禁止访问(例如:你没有权限访问/禁止访问)

​ 404 => 请求资源被拒绝(例如: 地址写错/页面删除了/没有网)

​ 408 => 客户端请求超时

500 内部服务器错误, 5开头的一般都是指服务器错误

// 发请求 保存返回的结果
const result = await httpRequest.request(urlStr, config)
if (result.responseCode === 401) {
      // 401 表示token失效 超时 或者没传
      // 提示错误 -删除目前的token 跳到登录页
      promptAction.showToast({ message: '登录失效' })
      // 删除token
      auth.setUser({} as User)
      router.replaceUrl({
        url: 'pages/Login/Login' // 跳转到登录页
      })
      // 当登录失效,return给提示 且不再往下执行
      return Promise.reject(new Error("登录失效"))
    }

token错误处理完后,我们处理一下404错误(请求资源被拒绝时)

else if (result.responseCode === 404) {
      promptAction.showToast({ message: '请求地址错误' })
      return Promise.reject(new Error("请求地址错误"))
    }

当以上两种错误都不存在时,我们假设此时已经请求成功(因为只有状态码为200时才成功)且每个接口返回的类型是一样的,比如 { code, data, msg }code为状态码,data是我们想要拿到的结果,msg是提示信息。那么我们定义一个类,来进一步完善我们拿到的结果,也就是拿到的结果直接就是data,而且因为每个接口返回的data的类型不一样(同时也不是每个接口返回的data我们都需要),所以这里又要用到泛型加联合类型。

export class ResponseData<T> {
  code: number = 0
  msg: string = ""
  // data 可选项
  data: T | null = null 
}

else {
      // 假设已经成功 此时不一定成功  还有业务状态码 只有业务状态码 200的时候才成功
      const res = JSON.parse(result.result as string) as ResponseData<T> // { code, data, msg }
      if (res.code === 200) {
        // 才认为这次请求真的成功了
        return res.data as T
      } else {
        // 业务错了
        promptAction.showToast({ message: "服务器异常" }) //  res.msg没处理好 有可能出来一堆服务器语言
        return Promise.reject(new Error(res.msg)) // 业务错误 请求终止
      }
    }

到此为止还差最后一步,我们对一些错误已经处理好了,但是我们不敢保证除了上边的错误之外还会不会存在其它错误,所以我们用try{}catch{}来捕获一下。

  try {
    // 发请求
    const result = await httpRequest.request(urlStr, config) // 发请求
    // 这里要处理一些异常
    // 判断状态码 http状态码 业务状态码
    if (result.responseCode === 401) {
      // 401 表示token失效 超时 或者没传
      // 提示错误 -删除目前的token 跳到登录页
      promptAction.showToast({ message: '登录失效' })
      // 删除token
      auth.setUser({} as User)
      router.replaceUrl({
        url: 'pages/Login/Login' // 跳转到登录页
      })
        // 当登录失效,return给提示 且不再往下执行
      return Promise.reject(new Error("登录失效"))
    } else if (result.responseCode === 404) {
      promptAction.showToast({ message: '请求地址错误' })
      return Promise.reject(new Error("请求地址错误"))
    } else {
      // 假设已经成功 此时不一定成功 还有业务状态码 只有业务状态码 200的时候才成功
      const res = JSON.parse(result.result as string) as ResponseData<T> // { code, data, msg }
      if (res.code === 200) {
        // 才认为这次请求真的成功了
        return res.data as T
      } else {
        // 业务错了
        promptAction.showToast({ message: "服务器异常" }) //  res.msg没处理好 有可能出来一堆服务器语言
        return Promise.reject(new Error(res.msg)) // 业务错误 请求终止
      }
    }
  } catch (error) {
    promptAction.showToast({ message: error.message }) //  res.msg没处理好 有可能出来一堆服务器语言
    return Promise.reject(error) // 业务错误 请求终止
  }

接下来我们就可以定义请求方法了

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 delete<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.DELETE, data)
  }

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

完整代码:

const BASE_URL = 'https://.....'  // 请求基础地址

export class ResponseData<T> {
  code: number = 0
  msg: string = ""
  // data 可选项
  data: T | null = null 
}
// T为泛型,用来定义响应类型
async function requestHttp<T>(url: string = "", method: http.RequestMethod = http.RequestMethod.GET,
  data?: object): Promise<T> {
  // http需要创建一个请求对象
  const httpRequest = http.createHttp() // 创建一个请求对象
  let urlStr = BASE_URL + url // 基础地址拼接url地址
	//判断是不是get请求
  if (method === http.RequestMethod.GET) {
    if (data && Object.keys(data).length) {
      // data参数都拼接到地址上  ?a=1&b=2&c=3
      //filter 过滤掉为空的参数 避免出现错误
      urlStr += "?" + Object.keys(data).filter(key =>
      !!data[key]).map(key => {
        return `${key}=${data[key]}`
      }).join("&")
    }
  }
  // 组装参数
  const config: http.HttpRequestOptions = {
    extraData: method !== http.RequestMethod.GET ? data : "", // 当请求类型不等于get时
    header: {
      Authorization: AppStorage.get(TOKEN_KEY) || "", // 设置请求头的token 
    },
    method,
    readTimeout: 20000 // 如果多少秒没响应就断开
  }

  try {
    // 发请求
    const result = await httpRequest.request(urlStr, config) // 发请求
    // 这里要处理一些异常
    // 判断状态码 http状态码 业务状态码
    if (result.responseCode === 401) {
      // 401 就表示token失效 超时 或者没传
      // 提示错误 -删除目前的token 跳到登录页
      promptAction.showToast({ message: '登录失效' })
      // 删除token
      auth.setUser({} as User)
      router.replaceUrl({
        url: 'pages/Login/Login' // 跳转到登录页
      })
        
      return Promise.reject(new Error("登录失效"))
    } else if (result.responseCode === 404) {
      promptAction.showToast({ message: '请求地址错误' })
      return Promise.reject(new Error("请求地址错误"))
    } else {
      // 假设已经成功 此时不一定成功  还有业务状态码 只有业务状态码 200的时候才成功
      const res = JSON.parse(result.result as string) as ResponseData<T> // { code, data, msg }
      if (res.code === 200) {
        // 才认为这次请求真的成功了 
        return res.data as T
      } else {
        // 业务错了
        promptAction.showToast({ message: "服务器异常" }) //  res.msg没处理好 有可能出来一堆服务器语言
        return Promise.reject(new Error(res.msg)) // 业务错误 请求终止
      }
    }
  } catch (error) {
    promptAction.showToast({ message: error.message }) //  res.msg没处理好 有可能出来一堆服务器语言
    return Promise.reject(error) // 业务错误 请求终止
  }

}

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 delete<T>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.DELETE, data)
  }

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

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐