likes
comments
collection
share

Vue3+TS版本Uniapp:封装uni.request请求配置

作者站长头像
站长
· 阅读数 10

作者:前端小王hs

阿里云社区博客专家/清华大学出版社签约作者✍/CSDN百万访问博主/B站千粉前端up主

封装拦截器

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中,需要使用到一个官方的APIuni.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+点击查看内置的接口信息,如下图所示: Vue3+TS版本Uniapp:封装uni.request请求配置

转载自:https://juejin.cn/post/7360242772303626277
评论
请登录