接口请求

接口请求函数request位于文件@/utils/request.ts中,基于axiosopen in new windowvue-request v2.xopen in new window二次封装,使用前请先阅读axiosopen in new windowvue-request v2.xopen in new window文档

核心代码如下:

/**
 * 请求函数
 * @param axiosConfig  axios的配置项
 * @param options vue request配置项+自定义配置项参考 RequestOptions
 * @param returnAxios
 * @returns
 */
export function request<R, P extends unknown[] = [], T = boolean>(
  axiosConfig: (...args: P) => AxiosRequestConfig | Promise<AxiosRequestConfig>,
  options?: RequestOptions<R, P>,
  returnAxios?: T,
) {
  const axiosService = async (...args: P): Promise<R> => {
    try {
      //loading放到微任务中去执行以确保在自动调用请求时等待所有的宏任务中的生命周期函数执行完再创建loading实例 以规避currentInstance的相关警告
      !options?.noLoading && Promise.resolve(undefined).then(loading);
      const { data: res } = await service(await axiosConfig(...args));
      if (!res || res.code === undefined) {
        throw Error(t('返回值解析失败'));
      }
      // 401:认证失败
      if (res.code === '401') {
        await useUserStore().logOut();
        return res;
      }
      if (res.code !== '200') {
        throw Error(res.msg);
      }
      if (options?.success) {
        ElMessage.success({ message: res.msg });
      }
      !options?.noLoading && closeLoading();
      return options?.needAll ? res : res.data;
    } catch (e) {
      !options?.noLoading && closeLoading();
      !options?.noError &&
        ElMessage.error({
          message: e instanceof Error ? e.message : String(e),
        });
      throw e;
    }
  };

  return returnAxios ? axiosService : useRequest<R, P>(axiosService, options);
}

自定义返回值格式

request函数主要是封装vue-request使其发起请求使用axios,并且请求时加上了loading、对接口返回值进行了校验处理、出错时自动报错提示

接口处理格式仅为示例格式,实际使用需要根据自己的项目规范修改以下代码

if (!res || res.code === undefined) {
  throw Error('返回值解析失败');
}
// 401:认证失败
if (res.code === '401') {
  await useUserStore().logOut();
  return res;
}
if (res.code !== '200') {
  throw Error(res.msg);
}

!options?.noLoading && closeLoading();
return options?.needAll ? res : res.data;

入参说明

参数类型说明是否必填
axiosConfigAxiosRequestConfig接口请求数据,完全遵循 axios configopen in new window 的规则
optionsRequestOptions基于vue-request optionsopen in new window配置扩展了个别配置,下面会详细说名
returnAxiosboolean返回axios,当传入true是返回axios不传或false时返回vue-reques对象
RequestOptions类型说明是否必填
needAllboolean返回完整的返回值忽略格式化返回值(默认返回的是data字段)
noLoadingboolean不需要lodaing
noErrorboolean不需要报错
... vue-request optionsvue-request optionsopen in new window更多字段参考vue-request optionsopen in new window 文档

使用示例

  • 在接口文件夹@/api文件夹中新建接口文件@/api/example.ts

  • @/api/example.ts加入接口声明代码

import request from '@/utils/request';

const enum Api {
  LIST = '/api/list',
}

export interface ListParams {
  page: number;
  size: number;
}
export interface ListResult {
  total: number;
  list: string[];
}
//导出列表接口
export function listApi() {
  return request<ListResult, [ListParams]>((params) => ({
    url: Api.LIST,
    method: 'get',
    params,
  }));
}
  • vue文件中使用
<template>
  <div class="list" v-loading="loading">
    <template v-if="data">
      <div v-for="(item, index) in data" :key="index">
        {{ item }}
      </div>
    </template>

  </div>
</template>
<script setup lang="ts" name="request">
import { listApi } from '@/api/example';
const { runAsync, loading, error, data } = listApi();
runAsync({page:1,size:10});//请求接口 建议使用runAsync请求而不是run,区别请参考文档https://next.cn.attojs.org/api/#runasync
</script>

自动请求示例

  • 在接口文件夹@/api文件夹中新建接口文件@/api/example.ts

  • @/api/example.ts加入接口声明代码

import request from '@/utils/request';

const enum Api {
  LIST = '/api/list',
}

export interface ListParams {
  page: number;
  size: number;
}
export interface ListResult {
  total: number;
  list: string[];
}
//导出列表接口
export function listApi(options: RequestOptions<ListResult, [ListParams]>) {
  return request(
    (params) => ({
      url: Api.LIST,
      method: 'get',
      params,
    }),
    options,
  );
}
  • vue文件中使用
<template>
  <div class="list" v-loading="loading">
    <template v-if="data">
      <div v-for="(item, index) in data" :key="index">
        {{ item }}
      </div>
    </template>

  </div>
</template>
<script setup lang="ts" name="request">
import { listApi } from '@/api/example';
const { runAsync, loading, error, data } = listApi({ defaultParams: [{ page: 1, size: 10 }], manual: false });//manual代表组件加载后自动请求接口
</script>

setup外请求示例

vue-request 是专门为setup使用的一个类库,详情请参考issues:149open in new window。 在setup外使用时应该直接使用axios,request函数允许接收一个参数直接返回axios实例

  • @/api/routeMenu.ts加入接口声明代码
import { request, RequestOptions } from '@/utils/request';
import { RouteRecordRaw } from 'vue-router';

const enum Api {
  MENU = '/api/menu/list',
}

export function menuApi<T extends boolean = true>(
  options: RequestOptions<RouteRecordRaw[], []> = {},
  returnAxios: T = true as T,
) {
  return request(
    () => ({
      url: Api.MENU,
      method: 'get',
    }),
    options,
    returnAxios,
  );
}

  • 在setup外使用
console.log(await menuApi()());