更新记录
1.1.6(2025-06-30) 下载此版本
优化无感刷新token后页面不更新的问题
1.1.5(2025-06-29) 下载此版本
优化无感刷新token
1.1.4(2025-06-27) 下载此版本
新增支持无感刷新token
查看更多平台兼容性
uni-app
Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
---|---|---|---|---|---|---|---|---|
√ | √ | - | - | √ | √ | - | - | - |
微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
---|---|---|---|---|---|---|---|---|---|---|
√ | - | - | - | - | - | - | - | - | - | - |
uni-app x
Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
---|---|---|---|---|---|
- | - | 5.0 | 12 | - | √ |
封装request promise写法 async+await 支持 GET,POST,PUT,DELETE,CONNECT,HEAD,OPTIONS,TRACE;
自定义请求头,更加灵活,自定义层业务层错误处理函数,支持多种外部url接口
支持无感刷新token
使用方法 App.vue代码如下
<script>
import { refreshTokenApi } from '@/apis/login.js'
export default {
globalData: {
baseUrl:'',
devUrl: 'http://devUrl.com',
proUrl: 'http://proUrl.com',
baiduUrl:'http:baidu.com',
httpSuccessCodes:[200, 201, 202, 203, 204, 205, 206], // http请求成功的状态码(必须是数组)
isRefreshing: false,
refreshSubscribers: [],
/**
* 业务层错误处理函数
*/
systemError(res) {
if (res.code === 401) {
// 需要刷新token的写法
// this.loginExpired(); // 调用刷新 Token
// return '登录过期,需要刷新token'; // 如果需要无感刷新token,这里的return的文字不能修改,如果不需要刷新token,那就注释掉this.loginExpired();return的文字也必须改掉,改成登录过期就行
// 不需要刷新token的写法
uni.showToast({
title: '登录过期',
icon: 'error'
});
uni.clearStorageSync();
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/login'
});
}, 1500);
return '登录过期';
}
if (res.code === 500) {
uni.showToast({
title: res.message,
icon: 'none',
duration: 2500
});
return res.message;
}
},
http401(){ //部分项目登录过期会把http状态码直接返回401,那么逻辑就可以写在这里
// 需要无感刷新的写法
// this.loginExpired(); // 调用刷新 Token
// return '登录过期,需要刷新token'; // 如果需要无感刷新token,这里的return的文字不能修改,如果不需要刷新token,那就注释掉this.loginExpired();return的文字也必须改掉,改成登录过期就行
// 不需要无感刷新
uni.showToast({
title: '登录过期',
icon: 'error'
});
uni.clearStorageSync();
setTimeout(() => {
uni.reLaunch({
url: '/pages/login/login'
});
}, 1500);
return '登录过期';
},
/**
* 刷新 Token 并处理请求队列
*/
loginExpired() {
const app = getApp();
if (app.globalData.isRefreshing) return;
app.globalData.isRefreshing = true;
refreshTokenApi()
.then((res) => {
uni.setStorageSync('token', res.data.accessToken);
uni.setStorageSync('refresh-token', res.data.refreshToken);
// 执行所有挂起的请求
app.globalData.refreshSubscribers.forEach(callback => callback());
app.globalData.refreshSubscribers = [];
})
.catch((err) => {
console.error('刷新 Token 失败:', err);
uni.clearStorageSync();
uni.reLaunch({ url: '/pages/login/login' });
})
.finally(() => {
app.globalData.isRefreshing = false;
});
},
/**
* 设置请求头
*/
setHeader(url,auth,formData) {
//也可以根据url的不同,动态设置header
let header = {
'content-type': 'application/json',
clientType: 'C',
communityId: uni.getStorageSync('communityId'),
Authorization:uni.getStorageSync('token')
};
// 一些项目的post的请求头需要设置为x-www-form-urlencoded,可以在接口里设置为formData = true
if (formData) {
header = {
...header,
'content-type': 'application/x-www-form-urlencoded',
};
}
// auth代表是否鉴权,默认是,如果不需要传Authorization等,可以在接口里设置为auth = false
if (!auth) {
delete header.Authorization;
}
return header
}
},
onLaunch: function () {
this.setBaseUrl();
},
onShow: function () {
console.log('App Show');
},
onHide: function () {
console.log('App Hide');
},
methods: {
/**
* 请求配置
*/
setBaseUrl() {
if (process.env.NODE_ENV === 'development') {
// 开发环境 运行
// #ifdef H5
this.globalData.baseUrl = location.origin;
// #endif
// #ifndef H5
this.globalData.baseUrl = this.globalData.devUrl;
// #endif
} else {
// 生产环境 发行
this.globalData.baseUrl = this.globalData.proUrl;
}
}
}
};
</script>
<style>
/*每个页面公共css */
</style>
如果有h5需要配置跨域代理,vue3项目在根目录创建vite.config.js,vue2的话是vue.congfig.js,同理代码如下
import { defineConfig } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
export default defineConfig({
plugins: [
uni(),
],
server: {
proxy: {
'/api/': {
target: 'http://pro.com',
changeOrigin: true,
}
},
},
});
根目录创建apis文件夹,用来放置接口文件 (文件夹名不要用api,因为h5配置代理会把所有api后的路径代理,所以要改成apis)
以apis文件的index.js为例,代码如下
import { request } from '@/uni_modules/yq-request/js_sdk/index';
/**
* 首页商品列表接口
*/
export const goodsPageApi = (data) =>
request({
api: '/api/goodsPage',
method:'post',
header:{'X-Custom-Header': 'custom-value'}, //支持自定义请求header,这里的header会替换qpp.vue中的全局header
data,
});
/**
* 首页商品列表接口 post的formData形式
*/
export const goodsApi = (data) =>
request({
api: '/api/goodsPage',
method:'post',
formData:true,
data
});
/**
* 首页商品列表接口 post的json形式
*/
export const goodsJsonApi = (data) =>
request({
api: '/api/goodsPage',
method:'post',
data
});
/**
* 首页公示公告列表接口 get
*/
export const newsApi = () =>
request({
api: "/api/listIndex",
});
/**
* 外部接口 get 不需要鉴权auth设置为false
*/
export const mapApi = () =>
request({
url:getApp().globalData?.baiduUrl, // 示例url
api: "/api/listIndex",
auth:false
});
在index.vue中使用 (vue3)
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
</view>
</template>
<script setup>
import { goodsApi, newsApi } from '@/apis/index';
import { onShow } from '@dcloudio/uni-app';
/**
* 获取商品
*/
const getGoods = async () => {
const res = await goodsApi();
console.log('res', res);
};
/**
* 获取公示公告
*/
const getNews = async () => {
const res = await newsApi();
console.log('res', res);
};
onShow(() => {
getGoods();
getNews();
});
</script>
在index.vue中使用 (vue2)
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
</view>
</template>
<script>
import { goodsApi, newsApi } from '@/apis/index';
export default {
data(){
return {
}
},
methods:{
/**
* 获取商品
*/
async getGoods() {
const res = await goodsApi();
console.log('res', res);
},
},
onShow() {
this.getGoods()
}
}
</script>