目录
前言
本专栏记录鸿蒙应用开发的一些知识,供鸿蒙开发者学习。笔者目前还是个小菜鸡,鸿蒙开发也是我看相关资料自学的,所以本文有些地方可能考虑不够周到,有些纰漏,就当抛砖引玉,还望读者海涵。目前HarmonyOS Next已经发布,API已更新至12,只有鸿蒙的开发者越来越多,才能更好的去改进HarmonyOS,去做好我们国人自己的系统,防止被别人卡脖子。本专栏适合初学者做一个入门,同时默认读者具备一定前端基础。本专栏的内容可以做一些课设,毕设之类的。但对于企业中的真实需求,可能考虑不够周到。因为笔者目前还没有工作(T_T)
本文主要讲解HarmonyOS Next开发http请求的封装。发送http请求需要申请ohos.permission.INTERNET权限。官方文档地址:http请求
版本说明:本文的API版本为12
一、业务场景
1、登录注册功能
在APP的登录注册功能中,我们往往需要访问后台数据库。用户登录时,输入账号和密码,点击登陆后,前端发起登录请求。后端接收到请求后,处理对应的逻辑,判断用户是否注册,密码是否正确等。
2、商品详情页功能
商品详情页功能,当我们点开某一个商品项的时候,前端将该商品的ID发送给后端,后端响应对应的商品详情信息给前端,前端再将数据进行一个渲染。
二、封装http请求
官方文档里的http开发指南比较全面,如果我们是做课设,或者是毕设,有些东西可以省去。下面我来讲解主要的步骤。
1、创建resultVO接口
前端发送请求后,后端返回的数据一般是如下格式:code--响应状态码;msg--响应信息;data--响应数据。响应数据data一般有多种类型,这里用泛型T接收,外部调用时,再指定T的类型。ArkTS是TypeScipt的超集,一般TS有的,ArkTS也有。所以ArkTS也支持泛型。
/*
* resultVO接口
* @code 响应码
* @msg 响应信息
* @data 响应数据
*/
export default interface resultVO<T>{
code: number
msg: string
data: T
}
2、创建requestParams接口
此接口用于规范调用http请求时的参数。
import { http } from '@kit.NetworkKit'
/*
* requestParams接口
* @url 必填 访问地址 (后端api访问地址)
* @method 选填(默认get) 请求方法 (get、post...)
* @extraData 选填(默认undefined ) 请求参数
*/
export interface requestParams{
url: string
method?: http.RequestMethod
extraData?: object
}
3、创建request文件,封装http请求
3.1 编写request方法
request方法需传入请求参数(requestParams接口),并返回一个Promise对象,该对象里面是resultVO<T>类型的数据。
/*
* request方法
* @params requestParams接口类型
* @@return Promise<resultVO<T>>
*/
export const request = async <T>(params: requestParams): Promise<resultVO<T>> => {
/*
* @resolve 请求成功
* @reject 请求失败
*/
return new Promise(async (resolve, reject) => {
})
}
3.2 返回Promise对象前,先获取一下关键参数
如果是本地模拟器访问本地的SpringBoot服务器,基地址为你所使用的电脑,它的IPv4地址。移动端项目和Vue项目不同,Vue项目的基地址一般是127.0.0.1,这个需要注意。我们这里把基地址设置成一个常量。要修改是,去常量类里面修改,提高代码的维护性。
token可以使用首选项进行存储和调用。首选项的知识可以看我的另外一篇文章:封装用户首选项
请求头一般是json类型,如有其他需求,可以更改。这个一般是和后端协调决定。如果自己做课设或者毕设,这里传一个token进来就可以了。
// 基地址。如果用本地模拟器访问,基地址一般为 “http://本机的IPv4地址:8080”
const baseURL: string = CommonConstants.BASE_URL
// 创建一个HttpRequest对象 -- 不可复用,一个httpRequest对象对应一个http请求
let httpRequest = http.createHttp()
// 获取token
let token: preferences.ValueType = await PreferenceUtil.getPreferenceValue(
CommonConstants.TOKEN, CommonConstants.NULL_TOKEN
)
// 完整请求地址
let requestUrl = baseURL + params.url
// 发起请求可选参数的类型和取值范围。
let options: http.HttpRequestOptions = {
// 请求类型,不传默认get
method: params.method ?? http.RequestMethod.GET,
// 请求头
// 做课设、毕设之类的,'Content-Type'默认'application/json'就好
// 请求头只用携带一个token,用于身份的校验
header: {
'Content-Type': 'application/json',
token
},
// 请求参数,不传默认undefined
extraData: params.extraData ?? undefined,
// 必填,不知道是不是bug,不填object类型,就会拿不到后端数据,和官方文档不一样
// 也可能是我后端接口的问题。----------这里存疑----------
expectDataType: http.HttpDataType.OBJECT
}
3.3 发送request请求
获取所需的参数之后,我们就可以发起request请求了,具体如下。请求成功后,记得销毁httpRequest对象,释放内存。
/*
* @resolve 请求成功
* @reject 请求失败
*/
return new Promise(async (resolve, reject) => {
/*
* 发送http请求
* @url 后端api完整地址
* @options 发起请求的可选参数
* @callback 回调函数
*/
httpRequest.request(
requestUrl,
options,
(err, data) => {
if (!err) {
// 处理请求成功的逻辑
// 获得后端返回过来的resultVO
const res = data.result as resultVO<T>
} else {
// 处理请求失败的逻辑
promptAction.showToast({message: CommonConstants.REQUEST_ERROR})
console.error('error:' + JSON.stringify(err))
reject(err)
}
// 销毁httpRequest对象
httpRequest.destroy()
}
)
})
3.4 根据业务需要处理请求后的逻辑
例1:拦截token过期
// token过期
if(res.code == CommonConstants.TOKEN_INVALIDATION){
promptAction.showToast({message: CommonConstants.TOKEN_INVALIDATION_MSG})
//清空历史页面
router.clear()
//跳转到登录页
router.replaceUrl({
url: CommonConstants.LOGIN_PAGE_URL
})
return
}
例2:处理正确状态码
// 判断响应码
if(res.code == CommonConstants.CODE_SUCCESS){
// 返回想要的的结果
resolve(res)
}else {
promptAction.showToast({message: res.msg})
return
}
三、完整文件代码
文件1:常量类
export class CommonConstants {
static readonly BASE_URL: string = 'http://192.168.31.160:8080'
// global data key
static readonly G_STORE: string = 'GreenTreasureStore';
static readonly TOKEN: string = 'TOKEN'
static readonly NULL_TOKEN: string = null
static readonly TOKEN_INVALIDATION : number = 401
static readonly CODE_SUCCESS : number = 1
static readonly TOKEN_INVALIDATION_MSG : string = 'token过期,请重新登录'
static readonly REQUEST_ERROR : string = '请求失败'
static readonly LOGIN_PAGE_URL : string = '/pages/Login/Index'
}
文件2:resultVO接口
/*
* resultVO接口
* @code 响应码
* @msg 响应信息
* @data 响应数据
*/
export default interface resultVO<T>{
code: number
msg: string
data: T
}
文件3:requestParams接口
import { http } from '@kit.NetworkKit'
/*
* requestParams接口
* @url 必填 访问地址 (后端api访问地址)
* @method 选填(默认get) 请求方法 (get、post...)
* @extraData 选填(默认undefined ) 请求参数
*/
export interface requestParams{
url: string
method?: http.RequestMethod
extraData?: object
}
文件4:request文件
import { http } from '@kit.NetworkKit'
import { preferences } from '@kit.ArkData'
import PreferenceUtil from '../utils/PreferencesUtil'
import resultVO from '../common/impl/resultVO'
import { CommonConstants } from '../constants/CommonConstants'
import { requestParams } from '../common/impl/requestParams'
import { promptAction, router } from '@kit.ArkUI'
/*
* request方法
* @params requestParams接口类型
* @@return Promise<resultVO<T>>
*/
export const request = async <T>(params: requestParams): Promise<resultVO<T>> => {
// 基地址。如果用本地模拟器访问,基地址一般为 “http://本机的IPv4地址:8080”
const baseURL: string = CommonConstants.BASE_URL
// 创建一个HttpRequest对象 -- 不可复用,一个httpRequest对象对应一个http请求
let httpRequest = http.createHttp()
// 获取token
let token: preferences.ValueType = await PreferenceUtil.getPreferenceValue(
CommonConstants.TOKEN, CommonConstants.NULL_TOKEN
)
// 完整请求地址
let requestUrl = baseURL + params.url
// 发起请求可选参数的类型和取值范围。
let options: http.HttpRequestOptions = {
// 请求类型,不传默认get
method: params.method ?? http.RequestMethod.GET,
// 请求头
// 做课设、毕设之类的,'Content-Type'默认'application/json'就好
// 请求头只用携带一个token,用于身份的校验
header: {
'Content-Type': 'application/json',
token
},
// 请求参数,不传默认undefined
extraData: params.extraData ?? undefined,
// 必填,不知道是不是bug,不填object类型,就会拿不到后端数据,和官方文档不一样
// 也可能是我后端接口的问题。----------这里存疑----------
expectDataType: http.HttpDataType.OBJECT
}
/*
* @resolve 请求成功
* @reject 请求失败
*/
return new Promise(async (resolve, reject) => {
/*
* 发送http请求
* @url 后端api完整地址
* @options 发起请求的可选参数
* @callback 回调函数
*/
httpRequest.request(
requestUrl,
options,
(err, data) => {
if (!err) {
// 处理请求成功的逻辑
console.info('httpRequest','code:' + JSON.stringify(data.result['code']))
console.info('httpRequest','msg:' + JSON.stringify(data.result['msg']))
console.info('httpRequest','data:' + JSON.stringify(data.result['data']))
// 获得后端返回过来的resultVO
const res = data.result as resultVO<T>
// token过期
if(res.code == CommonConstants.TOKEN_INVALIDATION){
promptAction.showToast({message: CommonConstants.TOKEN_INVALIDATION_MSG})
//清空历史页面
router.clear()
//跳转到登录页
router.replaceUrl({
url: CommonConstants.LOGIN_PAGE_URL
})
return
}
// 判断响应码
if(res.code == CommonConstants.CODE_SUCCESS){
// 返回想要的的结果
resolve(res)
}else {
promptAction.showToast({message: res.msg})
return
}
} else {
// 处理请求失败的逻辑
promptAction.showToast({message: CommonConstants.REQUEST_ERROR})
console.error('error:' + JSON.stringify(err))
reject(err)
}
// 销毁httpRequest对象
httpRequest.destroy()
}
)
})
}
四、发送request请求
1、开启网络权限
想要发送http请求,必须开启网络权限。网络权限开启步骤如下:
1.1 找到文件entry/src/main/module.json5
1.2 进入文件module.json5,在【module】的下一级,加上:
"requestPermissions":[
{
"name" : "ohos.permission.GET_NETWORK_INFO",
},
{
"name" : "ohos.permission.INTERNET",
}
],
2、测试登录请求
可以自己找一些后端接口进行测试。这里是笔者自己写的后端接口。后端接口的编写本文暂时不讲。读者可以自己试着写写看。
2.1 创建LoginDTO接口
该接口规范登录请求的参数
export interface LoginDTO{
userPhone: string
password: string
}
2.2 测试
import { LoginDTO } from '../common/dto/LoginDTO'
import { request } from '../utils/request';
import { http } from '@kit.NetworkKit';
const login = (loginDto: LoginDTO) => {
return request<string>({
url: `/user/api/login?userPhone=${loginDto.userPhone}&password=${loginDto.password}`,
method: http.RequestMethod.POST,
})
}
@Entry
@Component
struct Index {
async aboutToAppear() {
const res = await login({userPhone: '13652576888',password:'123456'})
}
build() {
}
}
2.3 结果
附录
参考文章:https://blog.csdn.net/sd1sd2/article/details/139536268
文章结束,如有纰漏还望指正。可以在评论区留下自己的想法。思想的碰撞是自我提升的催化剂,可以激发创新和进步。