HTTP封装
泛型封装后得出的代码:
typescript
复制代码
export class HdHttp {
// 1.统一封装post请求方法
static async post<T>(url: string, extraData?: Object) {
try {
// 1.0 创建http请求对象,并将请求对象命名为options
const httpReq = http.createHttp()
let options: http.HttpRequestOptions = {
method: http.RequestMethod.POST,
header: {
"Content-Type": "application/json"
},
expectDataType: http.HttpDataType.OBJECT
}
// 1.1 判断extraData可选参数如果不为空,则要将其追加到options对象中
if (extraData) {
options.extraData = extraData
}
// 1.2从AppStorage('user')中获取数据token,如果有值则追加到options.header中的Authorization
let user = AppStorage.get('user') as iLoginUserModel
// 使用user?写法,就能规避bug:在undefined上点出token这个属性报错
let token = user?.token
if (token && options.header) {
options.header['Authorization'] = `Bearer ${token}`
}
// 1.3 将动态构建好的options参数和url传给request->发请求获取服务器的响应数据
url = baseUrl + url
let res = await httpReq.request(url, options)
AlertDialog.show({message:JSON.stringify(res.result,null,2)})
// 1.5 优化功能:增加对登录是否成功的校验
// 增加服务器响应的code如果为401,是token失效,则重新登录获取新的有效token
let resdata = res.result as iResponseModel
// 如果服务器响应回来的数据不为10000,则表示有错误,则提示出错误信息
if (resdata.code !== 10000) {
// 如果服务器响应回来的code为401表示token失效,应该重新登录
if (resdata.code === 401) {
// token失效,重新登录
promptAction.showToast({ message: 'token失效,请重新登录' })
router.replaceUrl({ url: 'pages/LoginPage' })
} else {
promptAction.showToast({ message: resdata.message })
}
}
// 1.4 将服务器的数据返回
return resdata
} catch (err) {
promptAction.showToast({ message: '网络请求错误' })
return Promise.reject(err)
}
}
}
上述代码完整版本编写步骤与逻辑整理如下:
一、提取所有请求的url中的域名当做一个基本地址
二、对Http的Get和Post方法进行封装,写入HdHttp类中
统一封装post请求方法
1.0创建http请求对象,并将请求对象命名为options
1.1 判断extraData可选参数如果不为空,则要将其追加到options对象中
1.2从AppStorage('user')中获取数据token,如果有值则追加到options.header中的Authorization
1.3 将动态构建好的options参数和url传给request->发请求获取服务器的响应数据
1.4 将服务器的数据返回
1.5 优化功能:增加对登录是否成功的校验
封装get请求方法
——如果要向get请求的url传参,由调用者决定来是否在url后面进行拼接(拼接方式示例:get('clockinInfo')、get('clockinInfo?year=2024&moth=04'))
2.1 创建向服务器传信息的对象
2.2 获取token传给服务器(存于AppStorage中)
2.3 发送http请求
2.4 处理http响应,判断响应数据的集中情况
2.5 将服务器的响应数据返回
将本项目中的相关get、post的html代码需要替换为封装后的简化使用方式:
目前优先操作三个替换位置:
位置1:登录请求改造
位置2:获取当年当月的连续打卡数据
位置3:完成打卡动作
以替换位置1为例:
在登录请求改造中,由于没有定义泛型,无法确定post相关的数据结构,代码的编写一团雾水。
出现了很多类型相关的报错
那么这里post相关的数据结构具体指哪方法的数据结构呢?
根据以下的对比分析做一下思考和总结:
(1)如以上两个代码片段的分析可知,打卡动作中,主要有http请求信息、获取服务器响应结果(并进行数据转换)等步骤,期中需要封装的主要是http请求发送并获取相应结果的步骤。因此,泛型T在之列代表的是返回的结果。
(2)在上面的两个需要封装的内容中,由两个部分的信息是变化的,图中用方框记行了表示,Get方法的封装中有两个方框,分别代表了要传入封装方法中的参数和之后要返回的结果的数据类型
以POST方法在原LoginPage未封装(待封装)的部分进行说明
这里要对http请求返回的完整结果和经过处理后的结果做一个区分:如图,http返回的完整结果是包含responseCode、cookies、date、result等字段的完整内容,而result的格式则是我们定义定义的接口所返回的必要格式内容,分别由success、code、message、data四个字段组成,而data作为键的字段所带出的值对象又包含有丰富的信息,这些信息也是由开发者设定的,通常由前端后端讨论后,通过后端程序员编写接口文档和相关后端服务器功能来实现。
http请求返回的完整结果:
根据以上梳理,对文章开头提出的问题我们可以得出这些总结:
1、封装有哪些前提?封装什么?
通常是重复使用的代码、操作过程复杂的代码才需要进行封装。
2、封装有哪些难点、易错点
(1)难点:封装复杂的代码时,尤其是内容功能多的代码时,如何梳理要封装的内容,如何确定要封装部分的参数、返回值
(2)易错:要封装替代的内容有多重返回值结果类型,使用不确认返回值结果类型的方式(即不使用泛型的方式)的方式封装,容易导致错误
3、怎么引用封装?
建立工具文件夹,专门存放各门类的封装工具(如本项目的封装文件均存放在ets/common/util文件夹下)
通过导入可引用的ArkTS文件中的类进行引用。(如本案例引用HdHttp类:import { HdHttp } from '../common/utils/request')
4、本次案例的经验总结
(1)http请求的原始结果是很长的一串数据,需要的返回结果存放在原始返回结构的result字段下。result字段则具有特定的结构,可由前后端协作制定
(2)在封装文件中,第一步先提取所有请求的url中的域名当做一个基本地址,这种方法有利于服务端更换(门户)地址时的代码修改,也有利于减少代码的冗余
(3)对于有多种返回值类型的方法体系需要封装时,一定要使用泛型界定返回值类型,提供更精确的识别、查改错误的功能