在开发一个鸿蒙项目的时候,我们经常需要编写大量冗长的 HTTP 请求和处理代码,这些代码不仅容易出错,而且难以维护。为了解决这一问题,封装 HTTP 就是一个好的办法。
这里我总结一下我最近做的一个IT类相关新闻资讯的一个 App,关于这个 App 的 HTTP 模块统一封装。
登录模块
首先登录模块是肯定需要进行登录接口的post请求
登录逻辑处理我大致画了一个流程图:
未封装前的部分登录代码贴图如下(考虑安全关系,我这里是把接口隐藏了一部分,各位友友可以换成你们自己的接口地址)
部分登录代码如下:(可自行拷贝)
try {
let res = await http.createHttp().request(接口地址, {
method: http.RequestMethod.POST,
header: { "Content-Type": "application/json" },
extraData: {
username: this.username,
password: this.password
},
expectDataType: http.HttpDataType.OBJECT
})
// AlertDialog.show({ message: JSON.stringify(res.result, null, 2) })
// 处理响应式数据
let resDate = res.result as iResponseModel
if (resDate.code !== 10000) {
promptAction.showToast({ message: resDate.message })
return
}
AppStorage.setOrCreate('user', resDate.data)
router.pushUrl({
url: "pages/Index"
})
}
catch (err) {
this.isAgree = false
}
}
打卡组件功能实现
打卡组件功能处理逻辑我也大致画了一个流程图,如下:
获取当年当月的连续打卡数据,代码贴图如下:
完成在HdClockIn.ets中get请求,获取打卡数据并完成判断显示最终结果部分代码如下:
async getClockData() {
try {
let res = await http.createHttp().request("接口地址", {
header: { "Authorization": `Bearer ${this.currentUser.token}` },
expectDataType: http.HttpDataType.OBJECT
})
// 拿到结果
// AlertDialog.show({ message: JSON.stringify(res.result, null, 2) })
// 处理结果
let resData = res.result as iResModel
// AlertDialog.show({ message: resData.data.clockinNumbers.toString() })
// AlertDialog.show({ message: JSON.stringify(resData, null, 2) })
this.clockCount = resData.data.clockinNumbers
// AlertDialog.show({ message: JSON.stringify(resData.data.clockins, null, 2) })
}
catch (err) {
}
}
未封装前的部分登录代码贴图如下:
部分登录代码如下:(可自行拷贝)
async ClockIn() {
try {
let res = await http.createHttp().request('接口地址', {
method: http.RequestMethod.POST,
header: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.currentUser.token}`
},
expectDataType: http.HttpDataType.OBJECT
})
// 服务器返回post请求数据
let resData = res.result as iResModel
this.clockCount = resData.data.clockinNumbers
}
catch (err) {
console.log('mylog', JSON.stringify(err))
}
}
总结
由上面三个post请求和get请求可以看出,它们有很多相同的地方可以提炼出来,所以我利用http模块结合泛型方法进行统一的post请求封装和利用http模块结合泛型方法进行统一的get请求封装。
其次,利用封装好的post泛型方法和get泛型方法改造登录请求逻辑和打卡请求逻辑。并且get和post泛型方法中,增加401判断,如果code===401则跳转到登录页面。
http模块统一封装代码如下
我是把封装提炼到一个工具文件,最后导出给其他文件使用:
在request.ets文件中,利用静态的泛型方法对http模块统一封装完整代码:
import { http } from '@kit.NetworkKit'
import { iLoginUserModel, iResponseModel } from '../../../ets/models/AccountModel'
import { promptAction, router } from '@kit.ArkUI'
const Basurl: string = '接口地址'
export class HdHttp {
static async post<T>(url: string, extraData?: object) {
try {
let options: http.HttpRequestOptions = {
method: http.RequestMethod.POST,
header: {
"Content-Type": "application/json",
},
expectDataType: http.HttpDataType.OBJECT
}
let user = AppStorage.get('user') as iLoginUserModel
let token = user?.token
if (token && options.header) {
options.header['Authorization'] = `Bearer ${token}`
}
if (extraData) {
options.extraData = extraData
}
url = Basurl + url
let res = await http.createHttp().request(url, options)
let resData = res.result as iResponseModel<T>
if (resData.code !== 10000) {
if (resData.code === 401) {
// token失效重新登录
promptAction.showToast({ message: "请重新登录" })
router.pushUrl({ url: "pages/LoginPage" })
}
else {
promptAction.showToast({ message: resData.message })
return Promise.reject(resData.message)
}
}
return resData
}
catch (err) {
promptAction.showToast({ message: "网络请求错误" })
return Promise.reject(err)
}
}
// get不需要extraData,因为参数可以拼接到url上面
static async get<T>(url: string) {
try {
let options: http.HttpRequestOptions = {
header: {
"Content-Type": "application/json"
},
expectDataType: http.HttpDataType.OBJECT
}
let user = AppStorage.get("user") as iLoginUserModel
let token = user.token
if (token && options.header) {
options.header["Authorization"] = `Bearer ${token}`
}
url = Basurl + url
let res = await http.createHttp().request(url, options)
let resData = res.result as iResponseModel<T>
if (resData.code !== 10000) {
if (resData.code === 401) {
// token失效重新登录
promptAction.showToast({ message: "请重新登录" })
router.pushUrl({ url: "pages/LoginPage" })
}
else {
promptAction.showToast({ message: resData.message })
return Promise.reject(resData.message)
}
}
return resData
}
catch (err) {
promptAction.showToast({ message: "网络请求错误" })
return Promise.reject(err)
}
}
}
我这里也把url提炼出来,是为了以后项目如果要修改url地址,比如,如果写了几十个url地址,我只需要修改一个地方即可。
最后利用封装好的http模块改造上面三个post请求和get请求,
如下: 首先导入封装好的http模块:
import { HdHttp } from '../utils/request';
最后使用:
let resData = await HdHttp.post<iData>('接口地址')
this.clockCount = resData.data.clockinNumbers
可以很直观看出,通过封装减少重复工作、提升开发效率。
注意:是接口返回的数据的类型,要自己定义数据类型。
本文正在参加华为鸿蒙有奖征文征文活动