更新记录

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>

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问