在
uni-app开发中,我们经常需要与后端服务器进行数据交互。为了提高开发效率、代码的可维护性以及降低重复代码的使用,我们通常会对网络请求进行封装。
二次封装的好处:
- 简化代码,易于管理,通过
.get()或者.post()等方法简单调用发送请求;- 请求前拦截,在
header中增加token字段,设置请求头;- 防止请求重复发送;
- 统一处理请求错误,根据请求回调状态码做出不同响应。
- 在请求库中实现全局的
loading功能,让用户在发送请求时能够看到加载动画,增强用户体验。
实现步骤:
1、首先在/utils/utils.js,定义toast, clearStorageSync, getStorageSync等方法。
/**
* 提示方法
* @param {String} title 提示文字
* @param {String} icon icon图片
* @param {Number} duration 提示时间
*/
export function toast(title, icon = 'none', duration = 1500) {
if(title) {
uni.showToast({
title,
icon,
duration
})
}
}
/**
* 设置缓存
* @param {String} key 键名
* @param {String} data 值
*/
export function setStorageSync(key, data) {
uni.setStorageSync(key, data)
}
/**
* 获取缓存
* @param {String} key 键名
*/
export function getStorageSync(key) {
return uni.getStorageSync(key)
}
/**
* 删除缓存
* @param {String} key 键名
*/
export function removeStorageSync(key) {
return uni.removeStorageSync(key)
}
/**
* 清空缓存
* @param {String} key 键名
*/
export function clearStorageSync() {
return uni.clearStorageSync()
}
2、在/utils/request.js文件,定义基础请求,接收路径(url),方法(method),参数(data),请求头(header)四个参数。
import {toast, clearStorageSync, getStorageSync} from './utils'
const BASE_URL = 'https://www.baidu.com'
// 统一处理路径,参数,请求方式
uni.addInterceptor('request', {
invoke(args) { //拦截前触发
args.url = BASE_URL + args.url
//设置带token请求头
if (getStorageSync('token')) args.header["token"] = getStorageSync('token')
},
success(args) { //成功回调拦截
if (!args || !args.statusCode) {
return Promise.reject("错误的消息内容。");
}
//处理状态码
if (args.statusCode !== 200) {
if(args.statusCode === 402){
toast("登录已过期,请重新登录")
clearStorageSync()
setTimeout(() => {
uni.navigateTo({
url: '/pages/User/Login'
})
},1000)
}else{
console.log(args,'args');
toast(args.message || "请求失败")
}
return Promise.resolve({ data: { code: args.statusCode,message:'请求失败' } });
}else{
if (!args.data || !args.data.code) {
return Promise.resolve(args);
}
//处理消息码
if (args.data && args.data.code !== 200) {
if (args.data.code === 402) {
toast("请先登录")
setTimeout(() => {
//调转到登录页面
uni.navigateTo({
url: "/pages/User/Login",
});
}, 1000);
return Promise.resolve(args);
}else{
toast(args.data.message || "无法发起请求")
return Promise.resolve(args);
}
}
}
//返回消息
return Promise.resolve(args)
},
fail() { //失败回调拦截
toast("无法发起请求")
},
})
// 同时发送异步代码的次数,防止一次点击中有多次请求,用于处理
let ajaxTimes = 0;
const baseRequest = async (url, method, data, header) => {
ajaxTimes++;
uni.showLoading({
title: "加载中",
mask: true,
})
const promise = new Promise((resolve, reject) => {
uni.request({
url: url,
data: data,
method:method || 'GET',
header: header?header:{},
success: (res) => {
//上面已经对错误进行了处理,直接返回的就是data
resolve(res);
},
fail: (err) => {
reject(err)
},
// 完成之后关闭加载效果
complete: () => {
ajaxTimes--;
if (ajaxTimes === 0) uni.hideLoading();
}
});
});
return Promise.resolve(promise);
}
const request = {};
['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
request[method] = (api, data, header) => baseRequest(api, method, data, header)
})
export default request
3、使用方式
在/api/user.js 文件
import request from '@/utils/request'
//个人信息
export const userInfo = data => request.get('/user/userInfo', data)
页面中使用:
import { userInfo } from '@/api/user.js'
export default {
onLoad() {
this.getUserinfo()
},
methods: {
async getUserinfo() {
let res = await userInfo()
}
}
}
结语
做
uni-app项目,都可以将请求二次封装,提高效率,减少冗余代码。