Skip to Content
🎉 Nextra 4.0 is released. dimaMachina is looking for a new job or consulting.
请求使用

获取请求的基础路径

const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y'; const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);

isHttpProxy 用于判断是否使用代理,baseURL 表示环境文件中 VITE_SERVICE_BASE_URL 的值,otherBaseURL 用于其他请求,通过 VITE_OTHER_SERVICE_BASE_URL 配置。

getServiceBaseURL 方法用于获取请求的基础路径,根据环境变量 import.meta.envisHttpProxy 判断是否使用代理。

导入请求实例创建函数

可以选择 createRequest 或者 createFlatRequest 创建请求实例。

import { createFlatRequest, createRequest } from '@sa/axios';

具体见下方的案例

确认创建请求实例函数的范型参数

  • 请求结果的数据类型: App.Service.Response,默认请求用该类型,请根据自己的后端返回数据类型进行修改

    因为不同的类型会影响到 RequestOption 中的 isBackendSuccesstransformBackendResponse 以及错误信息的字段的参数类型

    其他请求实例的数据类型请自行再定义新的类型声明

  • 请求实例的状态类型: InstanceState,用于存储请求实例的一些状态,例如:表示是否正在刷新 token, 是否有错误弹窗展示等,根据自己的业务需求自行定义状态类型

创建请求实例 request

示例

import type { AxiosResponse } from 'axios'; import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios'; import { useAuthStore } from '@/store/modules/auth'; import { localStg } from '@/utils/storage'; import { getServiceBaseURL } from '@/utils/service'; import { $t } from '@/locales'; import { handleRefreshToken } from './shared'; const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y'; const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy); interface InstanceState { /** 是否有请求正在执行刷新token */ isRefreshingToken: boolean; } export const request = createFlatRequest<App.Service.Response, InstanceState>( { baseURL, headers: { apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2' } }, { async onRequest(config) { const { headers } = config; // 添加 token 到请求头 const token = localStg.get('token'); const Authorization = token ? `Bearer ${token}` : null; Object.assign(headers, { Authorization }); return config; }, isBackendSuccess(response) { // 当后端返回的 code 为 "0000"(默认) 时,表示请求成功 // 如果需要修改这个逻辑,可以在 `.env` 文件中修改 `VITE_SERVICE_SUCCESS_CODE` return response.data.code === import.meta.env.VITE_SERVICE_SUCCESS_CODE; }, async onBackendFail(response, instance) { const authStore = useAuthStore(); function handleLogout() { authStore.resetStore(); } function logoutAndCleanup() { handleLogout(); window.removeEventListener('beforeunload', handleLogout); } // 当后端返回的 code 在 `logoutCodes` 中时,表示用户需要退出登录 const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || []; if (logoutCodes.includes(response.data.code)) { handleLogout(); return null; } // 当后端返回的 code 在 `modalLogoutCodes` 中时,表示用户需要退出登录,通过弹窗形式提醒 const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || []; if (modalLogoutCodes.includes(response.data.code)) { // 防止用户刷新页面 window.addEventListener('beforeunload', handleLogout); window.$dialog?.error({ title: 'Error', content: response.data.msg, positiveText: $t('common.confirm'), maskClosable: false, onPositiveClick() { logoutAndCleanup(); }, onClose() { logoutAndCleanup(); } }); return null; } // 当后端返回的 code 在 `expiredTokenCodes` 中时,表示 token 过期,需要刷新 token // `refreshToken` 接口不能返回 `expiredTokenCodes` 中的错误码,否则会死循环,应该返回 `logoutCodes` 或 `modalLogoutCodes` const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || []; if (expiredTokenCodes.includes(response.data.code) && !request.state.isRefreshingToken) { request.state.isRefreshingToken = true; const refreshConfig = await handleRefreshToken(response.config); request.state.isRefreshingToken = false; if (refreshConfig) { return instance.request(refreshConfig) as Promise<AxiosResponse>; } } return null; }, transformBackendResponse(response) { return response.data.data; }, onError(error) { // 当请求失败时,可以在这里处理显示错误信息的逻辑 let message = error.message; let backendErrorCode = ''; // 获取后端返回的错误信息和错误码 if (error.code === BACKEND_ERROR_CODE) { message = error.response?.data?.msg || message; backendErrorCode = error.response?.data?.code || ''; } // 错误信息通过弹窗形式显示 const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || []; if (modalLogoutCodes.includes(backendErrorCode)) { return; } // 当 token 过期时,刷新 token 并重试请求,所以不需要显示错误信息 const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || []; if (expiredTokenCodes.includes(backendErrorCode)) { return; } window.$message?.error?.(message); } } );

使用请求实例

/** * 登录 * * @param loginRes 登录参数 */ export function fetchLogin(loginRes: Api.Auth.LoginReq) { return request<Api.Auth.LoginToken>({ url: '/auth/accounts/login', method: 'post', data: loginRes }); }

需要定义请求成功后的数据类型,例如:Api.Auth.LoginToken,并传入 request 函数中。

  • 如果 request 函数是通过 createFlatRequest 创建的,请求成功后的数据类型会被包装在一个对象中,可以通过 data 字段获取。
async function login() { const { error, data } = await fetchLogin({ username: 'admin', password: 'admin' }); if(!error) { // 请求成功 } }
  • 如果 request 函数是通过 createRequest 创建的,请求成功后的数据类型会直接返回,不会被包装在对象中。
async function login() { const data = await fetchLogin({ username: 'admin', password: 'admin' }); if(data) { // 请求成功 } }
Last updated on