存储token
当用户登录成功时,将用户信息持久化存储。
class Auth{
// 初始化用户
init(){
PersistentStorage.persistProp<User>(UserStoreKey,{} as User)
}
// 获取用户
getUser(){
return AppStorage.get<User>(UserStoreKey) || {} as User
}
// 设置用户
setUser(user: User){
AppStorage.setOrCreate<User>(UserStoreKey,user)
}
}
考虑到当用户没有登录时,点击了需要登录后才能进去的页面,再添加一个方法,跳转页面验证token,登录后直接进去页面,无需重新点击。
class Auth{
// 初始化用户
init(){
PersistentStorage.persistProp<User>(UserStoreKey,{} as User)
}
// 获取用户
getUser(){
return AppStorage.get<User>(UserStoreKey) || {} as User
}
// 设置用户
setUser(user: User){
AppStorage.setOrCreate<User>(UserStoreKey,user)
}
// 跳转页面方法,如果token有效直接跳转,无效时跳转到登录页,登录成功后跳转到之前想跳转的页面
// 访问权限控制 + 按钮控制
checkAuth(options: router.RouterOptions | Function){
const user = this.getUser()
// 根据是否有token判断是否有权限
// 两种情况:
// 路由跳转,跳转前检查token,如果没有跳转登录且需要携带,登录成功要跳转的地址
// 点击按钮,触发点击处理函数前判断token,如果没有跳转登录,返回即可
if(typeof options === 'function'){
if(user.token){
options()
}else {
router.pushUrl({url:'pages/LoginPage'})
}
}else {
if (user.token){
router.pushUrl(options)
}else {
const params = options.params as Record<string,string> || {}
params.router_url = options.url
router.pushUrl({
url:'pages/LoginPage',
params: params
})
}
}
// router.pushUrl()
}
}
export const auth = new Auth()
需要在登录按钮加 if 判断,用户有没有跳转页面触发登录。
// 可能存在需要回跳的页面
const params = router.getParams() as Record<string,string>
if (params?.router_url){
router.replaceUrl({url: params.router_url , params: params})
}else {
router.back()
}
请求工具封装
http请求工具封装可以使用官方提供的@ohos.net.http模块,也可以使用前端流行的axios封装。
使用axios封装首先在Terminal窗口中,执行如下命令安装三方包
ohpm install @ohos/axis
开通网络权限
需要配置ohos.permission.INTERNET权限,在工程目录entry\src\main中找到module.json5文件,配置网络请求权限。
封装的步骤:
首先,我们创建一个axios实例,并配置一些全局的默认值,比如baseURL(基础URL)、timeout(超时时间)等。
// 1. 创建 axios 实例
export const instance = axios.create({
baseURL: '基地址url',
// 请求超时时间10s, 如果超时会报错
timeout: 10000
})
然后,为axios实例添加请求拦截器,用于在请求发送前进行某些操作,比如添加token、设置请求头等。同样地,添加响应拦截器来处理响应数据。比如处理错误码、统一返回数据格式等。
// 添加响应拦截器
instance.interceptors.response.use((response: AxiosResponse) => {
// 对响应数据做点什么,取出后端给的data数据,将来你调用axios的时候,直接拿到的就是后台的data
// 如果业务失败,code不是10000,让axios调用的时候报错,否则就返回data数据
if (response.data.code === 10000) {
logger.debug('REQ SUCCESS', JSON.stringify(response.data.data))
return response.data.data
}
return Promise.reject(response.data);
}, (error: AxiosError) => {
logger.error('ERR',JSON.stringify(error))
// 报 401 错误登录失效返回登录页面
if(error.response?.status === 401){
// 用户信息token失效 清空用户信息
auth.setUser({} as User)
router.pushUrl({url: 'pages/LoginPage'},router.RouterMode.Single)
promptAction.showToast({ message: '登录失效' })
}
// 对响应错误做点什么
return Promise.reject(error);
});
// 请求拦截器
instance.interceptors.request.use((config: InternalAxiosRequestConfig) =>{
const user = auth.getUser()
if(user.token){
// 请求头携带token Bearer不固定
config.headers.Authorization = `Bearer ${user.token}`
}
return config
} ,(err: AxiosError) =>{
// logger.error('ERR',JSON.stringify(err))
return Promise.reject(err)
})
最后,根据实际需求封装具体的请求方法,如get、post、put、delete等,这些方法接收URL、请求参数、请求头和请求体,并返回一个包含响应数据、状态码和可能异常的封装对象,并导出这些封装好的方法供其他模块使用。
// 这里没有单独封装 get post delete post请求 需要用method来定义请求方式
class Http {
/**
* Res 响应数据类型
* Req 请求参数类型
* AxiosRequestConfig<Req> Req 是 post 请求 data 的类型
*/
request<Res, Req = Object>(config: AxiosRequestConfig<Req>) {
return instance.request<null, Res, Req>(config)
}
}
export const http = new Http()
通过以上步骤,我们可以有效地封装axios,实现HTTP请求的统一管理,增强代码的复用性和可维护性。同时,通过拦截器的使用,我们可以灵活地处理请求和响应,满足不同的业务需求。