鸿蒙开发NEXT基于原生http封装请求工具
文章介绍的是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)
}
}
更多推荐
所有评论(0)