作者:前端小王hs
阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主
封装请求配置项
- 封装拦截器
- 封装uni.request
封装拦截器
uniapp
的封装逻辑不同于Vue3
项目中直接使用axios.create()
方法创建实例(在create
方法中写入请求的地址、请求头、超时等内容),代码如下:
const instance = axios.create({
// 后端url地址
baseURL: import.meta.env.VITE_API_BASEURL,
timeout: 6000, //设置超时
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
PS:上述代码来自博主在B站的Vue3全家桶+MySQL+Express全栈实战项目源码
在uniapp
中,需要使用到一个官方的API
即uni.addInterceptor(STRING, OBJECT)
,这是一个用于拦截作用的API
,在规范开发的过程中,会在请求之前为请求的内容拼接url
、超时和请求头等信息,这一点在官方文档API
的基础拦截器一文中详细的示例,代码如下:
uni.addInterceptor('request', {
invoke(args) {
// request 触发前拼接 url
args.url = 'https://www.example.com/'+args.url
},
success(args) {
// 请求成功后,修改code值为1
args.data.code = 1
},
fail(err) {
console.log('interceptor-fail',err)
},
complete(res) {
console.log('interceptor-complete',res)
}
})
所以可以封装一个拦截器的配置项,为所有的uni.request
添加请求前置信息,代码如下:
const baseURL = import.meta.env.VITE_API_BASEURL
// 添加拦截器
const httpInterceptor = {
// 拦截前触发
invoke(options: UniApp.RequestOptions) {
// 假设开头为非http的请求url地址
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
// 请求超时
options.timeout = 6000
options.header = {
...options.header,
// 自定义标识符,用于后端区分app、后台或其他渠道请求
'source-client': 'app',
}
// 添加 token 请求头标识
const token = uni.getStorage('token')
if (token) {
options.header.Authorization = token
}
},
}
uni.addInterceptor('request', httpInterceptor)
这是一段万能的uniapp
封装拦截器代码,读者可收藏此文章粘贴即用,下同
封装uni.request
这里的封装,参考了axios
返回promise
对象的实现逻辑,在接口中return
一个promise
对象,便于在实际环境中更好的获取数据以及进一步处理数据,代码如下:
type Data<T> = {
// 后端返回的通用响应结构
statusCode: string
msg: string
result: T
}
// UniApp.RequestOptions为配置网络请求的选项
// 这里使用了泛型,便于自定义响应结构
export const http = <T>(options: UniApp.RequestOptions) => {
return new Promise<Data<T>>((resolve, reject) => {
uni.request({
// 拦截器配置内容
...options,
success(res) {
// 成功响应
handleResponse(res, resolve, reject);
},
fail(err) {
handleError(err, reject);
},
});
};
};
// resolve和reject不返回任何值,但通知promise更改状态
const handleResponse = <T>(res: any, resolve: (value: Data<T>) => void, reject: (reason?: any) => void) => {
// 分离了验证状态码逻辑
if (isSuccessStatusCode(res.statusCode)) {
resolve(res.data as Data<T>);
// 登录失败
} else if (res.statusCode === 401) {
// 假设 clearUserInfo 是清除用户信息的函数
clearUserInfo();
// 跳转至登录页面
uni.navigateTo({ url: '/pages/login/index' });
reject(res);
} else {
// 分离了报错状态码逻辑
showErrorToast(res.data as Data<T>);
reject(res);
}
};
const handleError = (err: any, reject: (reason?: any) => void) => {
uni.showToast({
icon: 'none',
title: '网络可能开小差了~',
});
reject(err);
};
const isSuccessStatusCode = (statusCode: number) => {
return statusCode >= 200 && statusCode < 300;
};
const showErrorToast = <T>(data: Data<T>) => {
uni.showToast({
icon: 'none',
title: data.msg || '请求错误',
});
};
关于RequestOptions
更多的信息,可以对其ctrl+点击
查看内置的接口信息,如下图所示: