Uniapp VUE3 request封装

  1. request.js 
import env from '@/env.js';
import store from '@/store/index.js';
import { getTimestamp, generateAppKey } from '@/util/common.js';

let isRefreshing = false;
let subscribers = [];

function onAccessTokenFetched(newToken) {
  subscribers.forEach((callback) => callback(newToken));
  subscribers = [];
}

function addSubscriber(callback) {
  subscribers.push(callback);
}

//获取token
export const fetchToken = async () => {
  const appid = env.appId;
  const secret = env.appSecret;
  const companycode = env.companyCode;
  const timestamp = getTimestamp();
  const appkey = generateAppKey(appid, timestamp, secret);

  try {
    const { data, statusCode } = await new Promise((resolve, reject) => {
      uni.request({
        url: `${env.WebApiBase}/accessToken/getToken`,
        method: 'GET',
        timeout: 10000,
        header: {
          'Content-Type': 'application/json',
        },
        data: {
          appid,
          appkey,
          timestamp,
          companycode,
        },
        complete: (response) => {
          const { statusCode, data } = response;
          if (statusCode === 200) {
            resolve({ data, statusCode });
          } else {
            reject(new Error(`请求失败,状态码:${statusCode}`));
          }
        },
        fail: (error) => {
          reject(new Error(`网络请求失败: ${error.errMsg}`));
        },
      });
    });

    if (data.Success) {
      store.dispatch('saveToken', data.GateWayToken);
      return data.GateWayToken;
    } else {
      throw new Error(`获取 Token 失败: ${data.Message || '未知错误'}`);
    }
  } catch (error) {
    if (error.message.includes('timeout')) {
      uni.showToast({ title: '请求超时,请检查网络连接', icon: 'none' });
    } else if (error.message.includes('网络请求失败')) {
      uni.showToast({ title: '网络错误,请稍后重试', icon: 'none' });
    } else {
      uni.showToast({ title: error.message, icon: 'none' });
    }

    console.error('获取 Token 失败:', error);
    throw error;
  }
};

const request = async (options = {}, retryCount = 0) => {
  if (!store.getters.getToken && !isRefreshing) {
    await store.dispatch('fetchAndSaveToken');
  }

  // 将data对象转为查询字符串
  let queryParams = '';
    // 首先,将 param 转换为 JSON 字符串
    if (options.data.param) {
        options.data.param = JSON.stringify(options.data.param);
    }
  if (options.data) {
    queryParams = Object.keys(options.data)
      .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(options.data[key])}`)
      .join('&');
  }

  // 确保只有在 options.url 不包含 WebApiBase 时才添加它
  const finalUrl = options.url.startsWith(env.WebApiBase)
    ? options.url
    : `${env.WebApiBase}${options.url}${queryParams ? (options.url.includes('?') ? '&' : '?') + queryParams : ''}`;

  // 更新 options 对象
  options.url = finalUrl;
  options.header = {
    'Content-Type': 'application/json;charset=UTF-8',
    GateWayToken: store.getters.getToken,
    ...options.header,
  };

  options.dataType = 'json';
  options.responseType = 'text';

  return new Promise((resolve, reject) => {
    options.complete = async (response) => {

      // 确保 response 对象不为空
      if (!response) {
        reject(new Error('响应为空'));
        return;
      }

      const { statusCode, data } = response || {};

      if (statusCode === 200) {
        // 检查业务逻辑中的401错误
        if (data.StatusCode === '401' && data.Message.includes('登录已超时')) {
          if (retryCount < 1) {
            handleTokenRefresh(async (newToken) => {
              options.header['GateWayToken'] = newToken;
              resolve(await request(options, retryCount + 1));
            });
          } else {
            handleUnauthorized();
            // reject(new Error('Token刷新失败,多次尝试无效'));
          }
        } else if (data.Success) {
          resolve(data.datalist);
        } else {
                    if(data.Message == '暂无数据'){
                        resolve([]);
                    }else{
                        reject(data);
                    }
        }
      } else {
        reject(data);
      }
    };

    uni.request(options);
  });
};

const handleTokenRefresh = (retryRequest) => {
  addSubscriber(retryRequest);

  if (!isRefreshing) {
    isRefreshing = true;
    store.dispatch('fetchAndSaveToken')
      .then((newToken) => {
        onAccessTokenFetched(newToken);
      })
      .catch(() => {
        // console.error('Token刷新失败:', error);
                handleUnauthorized();
                // throw new Error('Token刷新失败,多次尝试无效');
      })
      .finally(() => {
        isRefreshing = false;
      });
  }
};

const handleUnauthorized = () => {
  store.commit('resetState');
};

export default {
  request,
  get: (url, data, options) => request({ url, data, method: 'GET', ...options }),
  post: (url, data, options) => request({ url, data, method: 'POST', ...options }),
  put: (url, data, options) => request({ url, data, method: 'PUT', ...options }),
  delete: (url, data, options) => request({ url, data, method: 'DELETE', ...options }),
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UniApp是一个基于Vue.js的跨平台开发框架,可以同时开发iOS、Android、H5等多个平台的应用。Vue 3是Vue.js的最新版本,带来了许多新特性和改进。在UniApp中使用Vue 3和TypeScript来封装请求可以按照以下步骤进行: 1. 安装依赖:在UniApp项目中,首先需要安装axios库和@types/axios库,用于发送HTTP请求和提供TypeScript类型定义。 ```bash npm install axios @types/axios ``` 2. 创建请求封装文件:在项目的`src`目录下创建一个`api`文件夹,并在该文件夹下创建一个`request.ts`文件,用于封装请求相关的代码。 ```typescript import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; // 创建axios实例 const instance = axios.create({ baseURL: 'http://api.example.com', // 设置请求的基础URL timeout: 5000, // 设置请求超时时间 }); // 请求拦截器 instance.interceptors.request.use( (config: AxiosRequestConfig) => { // 在发送请求之前做一些处理,例如添加token等 return config; }, (error) => { // 处理请求错误 return Promise.reject(error); } ); // 响应拦截器 instance.interceptors.response.use( (response: AxiosResponse) => { // 对响应数据进行处理,例如统一处理错误码等 return response.data; }, (error) => { // 处理响应错误 return Promise.reject(error); } ); // 封装GET请求 export function get(url: string, params?: any): Promise<any> { return instance.get(url, { params }); } // 封装POST请求 export function post(url: string, data?: any): Promise<any> { return instance.post(url, data); } // 其他请求方法的封装,例如PUT、DELETE等 ``` 3. 使用请求封装:在需要发送请求的地方,引入`request.ts`文件,并调用相应的请求方法。 ```typescript import { get, post } from '@/api/request'; // 发送GET请求 get('/user/info', { id: 1 }) .then((response) => { console.log(response); }) .catch((error) => { console.error(error); }); // 发送POST请求 post('/user/login', { username: 'admin', password: '123456' }) .then((response) => { console.log(response); }) .catch((error) => { console.error(error); }); // 其他请求方法的使用,例如PUT、DELETE等 ``` 以上就是在UniApp中使用Vue 3和TypeScript封装请求的基本步骤。你可以根据实际需求进行进一步的封装和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值