use
Get the base path of the request
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);
isHttpProxyUsed to determine if a proxy is being used.baseURLindicates the value ofVITE_SERVICE_BASE_URLin the environment file.otherBaseURLis used for other requests, configured viaVITE_OTHER_SERVICE_BASE_URL.
The
getServiceBaseURLmethod is used to get the base path of the request, and determine if a proxy is used based on the environment variablesimport.meta.envandisHttpProxy.
Import request instance creation function
Request instances can be created with either createRequest or createFlatRequest.
import { createFlatRequest, createRequest } from '@sa/axios';See below for examples
Confirmation of Paradigm Parameters for the Create Request Instance Function
Data type of the request result:
App.Service.ResponseThe default request uses this type, please modify it according to your own back-end return data typeThis is because the different types affect the parameter types of the
isBackendSuccessandtransformBackendResponsefields inRequestOption, as well as the error message fields.Please define new type declarations for other request instances.
The state type of the request instance:
InstanceState,Used to store some state of the request instance, e.g. whether the token is being refreshed, whether there is an error pop-up window display, etc. Define the state type according to your business needs.
Creating a Request Instance request
Typical example
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 {
/** Whether there is a request being executed to refresh the token */
isRefreshingToken: boolean;
}
export const request = createFlatRequest<App.Service.Response, InstanceState>(
{
baseURL,
headers: {
apifoxToken: 'XL299LiMEDZ0H5h3A29PxwQXdMJqWyY2'
}
},
{
async onRequest(config) {
const { headers } = config;
// Add `token` to request header
const token = localStg.get('token');
const Authorization = token ? `Bearer ${token}` : null;
Object.assign(headers, { Authorization });
return config;
},
isBackendSuccess(response) {
// When the code returned by the backend is "0000" (default), it means the request is successful.
// If you need to change this logic, you can change the `VITE_SERVICE_SUCCESS_CODE` in the `.env` file.
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);
}
// When the code returned by the backend is in `logoutCodes`, it means that the user needs to log out.
const logoutCodes = import.meta.env.VITE_SERVICE_LOGOUT_CODES?.split(',') || [];
if (logoutCodes.includes(response.data.code)) {
handleLogout();
return null;
}
// When the code returned by the backend is in `modalLogoutCodes`, it means that the user needs to log out, which is reminded by a popup window.
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(response.data.code)) {
// Prevent users from refreshing the page
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;
}
// When the code returned by the backend is in `expiredTokenCodes`, the token is expired and needs to be refreshed.
// The `refreshToken` interface can't return error codes in `expiredTokenCodes`, otherwise it will die, it should return `logoutCodes` or `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) {
// When a request fails, the logic to display an error message can be handled here
let message = error.message;
let backendErrorCode = '';
// Get the error message and error code returned by the backend
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.msg || message;
backendErrorCode = error.response?.data?.code || '';
}
// Error messages are displayed in a pop-up window
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(backendErrorCode)) {
return;
}
// When the token expires, refresh the token and retry the request, so there's no need for an error message.
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(backendErrorCode)) {
return;
}
window.$message?.error?.(message);
}
}
);Example of using a request
/**
* Login
*
* @param loginRes Login parameters
*/
export function fetchLogin(loginRes: Api.Auth.LoginReq) {
return request<Api.Auth.LoginToken>({
url: '/auth/accounts/login',
method: 'post',
data: loginRes
});
}You need to define the type of data that will be used after a successful request, e.g. Api.Auth.LoginToken, and pass it into the request function.
- If the request function was created with
createFlatRequest, the data type of a successful request is wrapped in an object that can be retrieved from thedatafield.
async function login() {
const { error, data } = await fetchLogin({ username: 'admin', password: 'admin' });
if(!error) {
// Request successful
}
}- If the request function was created with
createRequest, the data type of a successful request is returned directly and is not wrapped in an object.
async function login() {
const data = await fetchLogin({ username: 'admin', password: 'admin' });
if(data) {
// Request successful
}
}