前言
hello 大家好!我是无言。 最近鸿蒙相关的开发需求日渐增多,我基于 @ohos.net.http
进行过封装用于项目开发,也有用axios开发过项目,其实整个的逻辑是非常相似的,但是作为一个前端开发人员来讲,axios
使用起来还是更加符合我们平时的开发习惯。所以本文来讲一讲如何封装axios
用于实际的鸿蒙项目开发。
一、准备工作
-
安装好最新DevEco Studio 开发工具,创建一个新的空项目。
-
下载安装
@ohos/axios
。
在项目对应模块下oh-package.json5
文件 dependencies
中输入"@ohos/axios": "2.2.2"
完成后参考下图点击执行 Sync Now
进行安装
- 创建网络请求工具文件
ets/utils/request.ets
- 创建统一管理接口文件
ets/api/index.ets
二、利用axios的create
方法创建 axios 实例
这里的作用主要有下面三个:
- 配置我们全局公共的网络请求前缀
baseURL
。 - 配置统一的超时时间
timeout
。 - 配置公共的统一
headers
。
request.ets
import axios,{InternalAxiosRequestConfig, AxiosResponse,AxiosError,AxiosRequestConfig,AxiosInstance} from '@ohos/axios';
// 创建实例
const instance: AxiosInstance = axios.create({
baseURL: 'http://XXX.XX.XX.XX', //修改为自己项目的实际地址
timeout: 10000,//超时
headers: { 'Content-Type': 'application/json' },
// `transformRequest` 允许在向服务器发送前,修改请求数据 一般来说用不到,只要后端同志是正常的
// 它只能用于 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
// 你可以修改请求头。
// transformRequest: [(data: ESObject, headers: AxiosRequestHeaders) => {
// // 对发送的 data 进行任意转换处理
// // console.log('api1Result出零四',data)
// // return data
// }],
});
三、配置添加请求拦截器
这里运用最多的场景也就是把身份信息Token
放入到header中携带过去传到后端。 这里还涉及到缓存信息,这个每个项目都有自己的考量,我在项目中一般用的腾讯的@tencent/mmkv,体验感还不错。
javascript
// 请求拦截器
instance.interceptors.request.use((config:InternalAxiosRequestConfig) => {
// 对请求数据做点什么
const token = 'eyJhbw'//自己根据自己项目实际情况获取
if(token){
config.headers['token']=token //设置token
}
return config;
}, (error:AxiosError) => {
// 对请求错误做些什么
return Promise.reject(error);
});
四、配置添加响应拦截器
下面内容用到了@ohos.router进行页面 跳转,用到了@kit.ArkUI'的promptAction.showToast
进行统一错误提示。
响应拦截非常重要,他是我们封装请求好用的关键,但是每个项目业务不同,其实响应拦截的配置都有不小的差异,但是整体思路是一致的,所以要根据自己的实际情况进行修改。
javascript
// 添加响应拦截器
instance.interceptors.response.use((response:AxiosResponse)=> {
// 对响应数据做点什么
// 因为 我们后台返回的 数据结构是统一的例如{code:2001,massage:'用户信息不能为空',data:{}}
// 所以下面配置根据系统返回来配置的,不同的系统配置不同
if(response.data.code=='2001'){ //这里是举例 要根据自己项目的实际情况进行处理
promptAction.showToast({ //用到了 @kit.ArkUI 的 promptAction进行系统弹窗提示
message: response.data.massage,
duration: 2000,
alignment:Alignment.Center
});
return Promise.reject(response.data);
}
if(response.data.code=='4001'){//这里是举例 要根据自己项目的实际情况进行处理
router.pushUrl({ //用到了 @ohos.router 进行页面跳转
url:"pages/LoginPage"
})
return Promise.reject(response.data);
}
return response.data;
}, (error:AxiosError)=> {
console.log("AxiosError",JSON.stringify(error.response))
const status = error.response?.status;
switch (status) {
case 401://无权限未登录
router.pushUrl({ //用到了 @ohos.router 进行页面跳转
url:"pages/LoginPage"
})
break;
default :
promptAction.showToast({ //用到了 @kit.ArkUI 的 promptAction进行系统弹窗提示
message: "系统异常,请稍后再试!",
duration: 2000,
alignment:Alignment.Center
});
break
}
return Promise.reject(error);
});
五、使用泛型T暴露我们请求的配置
在本例中我针对后端返回的数据结构如下
json
{
"code": 2001,
"message": "接口调用失败",
"data": { } //data的内容不是固定的可能是null,可能是对象,也可能是数组
}
因为我们接口返回结果不固定,所以我们利用一下Ts的 泛型暴露我们封装的请求。
axios封装的完整代码如下
typescript
import axios,{InternalAxiosRequestConfig, AxiosResponse,AxiosError,AxiosRequestConfig,AxiosInstance} from '@ohos/axios';
import router from '@ohos.router';
import { promptAction } from '@kit.ArkUI';
interface ApiResponse<T> { //根据项目实际项目修改
data: T;
message?: string;
code?: number;
}
// 创建实例
const instance: AxiosInstance = axios.create({
baseURL: 'http://XXX.XXX.XXX', //修改为自己项目的实际地址
timeout: 10000,//超时
headers: { 'Content-Type': 'application/json' },
});
//暴露封装请求--为什么没有把上面实例放入到下面中,避免每一个接口都去创建一次
//这里利用了泛型 T
export default <T>(config:AxiosRequestConfig): Promise<ApiResponse<T>>=> {
// 请求拦截器
instance.interceptors.request.use((config:InternalAxiosRequestConfig) => {
// 对请求数据做点什么
const token = 'eyJhbGciOiJ....'//自己根据自己项目实际情况获取我大部分用的 @tencent/mmkv 插件
if(token){
config.headers['authorization']=token //设置token
}
return config;
}, (error:AxiosError) => {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use((response:AxiosResponse)=> {
// 对响应数据做点什么
// 因为 我们后台返回的 数据结构是统一的例如{code:2001,massage:'用户信息不能为空',data:{}}
// 所以下面配置根据系统返回来配置的,不同的系统配置不同
if(response.data.code=='2001'){ //这里是举例 要根据自己项目的实际情况进行处理
promptAction.showToast({ //用到了 @kit.ArkUI 的 promptAction进行系统弹窗提示
message: response.data.massage,
duration: 2000,
alignment:Alignment.Center
});
return Promise.reject(response.data);
}
if(response.data.code=='4001'){//这里是举例 要根据自己项目的实际情况进行处理
router.pushUrl({ //用到了 @ohos.router 进行页面跳转
url:"pages/LoginPage"
})
return Promise.reject(response.data);
}
return response.data;
}, (error:AxiosError)=> {
console.log("AxiosError",JSON.stringify(error.response))
const status = error.response?.status;
switch (status) {
case 401://无权限未登录
router.pushUrl({ //用到了 @ohos.router 进行页面跳转
url:"pages/LoginPage"
})
break;
default :
promptAction.showToast({ //用到了 @kit.ArkUI 的 promptAction进行系统弹窗提示
message: "系统异常,请稍后再试!",
duration: 2000,
alignment:Alignment.Center
});
break
}
return Promise.reject(error);
});
return instance(config);
}
六、代码示例示范统一管理接口配置(测试)
在ets/api/index.ets
文件添加如下内容
csharp
import request from "../utils/request";
interface LoginParams{
phone:string;
code:string|number;
}
//测试登录
export function TestLogin<T>(data:LoginParams){
return request<T>({
url: "/test/login",
method: "post",
data
});
}
//测试信息列表
export function parkList<T>(params:Record<string,string>){
return request<T>({
url: "/test/parks",
method: "get",
params
});
}
七、代码示例示范调用(测试)
typescript
import {TestLogin } from "../api/index"
// 定义返回内容
interface ResponseLogin{
name:string;
code:string
}
@Entry
@Component
struct Index {
async setTestLogin(){
const result = await TestLogin<ResponseLogin>({phone:'13111111',code:352})
if(result){
console.log('result',JSON.stringify(result))
console.log('code',JSON.stringify(result.code))
console.log('data',JSON.stringify(result.data))
}
}
build() {
RelativeContainer() {
Button('测试').onClick(()=>{
this.setTestLogin();
})
}
.height('100%')
.width('100%')
}
}
八、其他题外话
我们知道在鸿蒙开发中类型校验非常严格,而且不允许有 any
类型,如果项目赶期,声明类型是一个非常麻烦的事情。其实鸿蒙开发中也有办法,就是不要用 .ets
后缀结尾。 可以 声明一个type.d.ts
文件,然后再其他.ets
文件中引入是不会报错的。
所以上面封装axios文件中
你要是嫌麻烦,也可以用下面的 类型去代替泛型T
。(不建议)
type.d.ts
//嵌套未知类型
export interface PromiseObject {
[key: string]: string | number |object| boolean |undefined| PromiseObject | PromiseObject[] | Array<string | number | boolean | PromiseObject |any>
}
// any 类型
export type anyType = any;
总结
上面针对Axios的封装,基本上就能够满足大部分业务需求了,当然还有取消请求
,断开重连
这些我认为用到的比较少,就没有加上,如果后续掘友们觉得有必要 我可以再加上。
本篇文章写到这里就结束了,我把代码放到了gitee上,如果觉得本篇文章对你有帮助欢迎来波三连。