2024-03-26 11:47:11 +08:00
import type { AxiosResponse } from 'axios' ;
2024-03-08 17:59:45 +08:00
import { BACKEND_ERROR_CODE , createFlatRequest , createRequest } from '@sa/axios' ;
2024-03-26 11:47:11 +08:00
import { useAuthStore } from '@/store/modules/auth' ;
2024-03-08 17:59:45 +08:00
import { localStg } from '@/utils/storage' ;
2024-03-21 10:57:53 +08:00
import { getServiceBaseURL } from '@/utils/service' ;
2024-03-26 11:47:11 +08:00
import { $t } from '@/locales' ;
import { handleRefreshToken } from './shared' ;
2024-03-08 17:59:45 +08:00
2024-03-21 10:57:53 +08:00
const isHttpProxy = import . meta . env . DEV && import . meta . env . VITE_HTTP_PROXY === 'Y' ;
const { baseURL , otherBaseURL } = getServiceBaseURL ( import . meta . env , isHttpProxy ) ;
2024-03-08 17:59:45 +08:00
2024-03-26 11:47:11 +08:00
interface InstanceState {
2024-03-28 16:22:18 +08:00
/** whether the request is logout */
isLogout : boolean ;
2024-03-26 11:47:11 +08:00
/** whether the request is refreshing token */
isRefreshingToken : boolean ;
}
export const request = createFlatRequest < App.Service.Response , InstanceState > (
2024-03-08 17:59:45 +08:00
{
2024-03-21 10:57:53 +08:00
baseURL ,
2024-03-26 11:47:11 +08:00
headers : {
timeout : 6000
}
2024-03-08 17:59:45 +08:00
} ,
{
async onRequest ( config ) {
const { headers } = config ;
// set token
const token = localStg . get ( 'token' ) ;
2024-03-21 11:53:27 +08:00
const namespaceId = localStg . get ( 'namespaceId' ) ;
// const Authorization = token ? `Bearer ${token}` : null;
headers [ 'EASY-RETRY-AUTH' ] = token ;
headers [ 'EASY-RETRY-NAMESPACE-ID' ] = namespaceId ;
Object . assign ( headers , { 'EASY-RETRY-AUTH' : token , 'EASY-RETRY-NAMESPACE-ID' : namespaceId } ) ;
2024-03-08 17:59:45 +08:00
return config ;
} ,
isBackendSuccess ( response ) {
2024-03-26 11:47:11 +08:00
// when the backend response code is "0000"(default), it means the request is success
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
return response . data . status . toString ( ) === import . meta . env . VITE_SERVICE_SUCCESS_CODE ;
2024-03-08 17:59:45 +08:00
} ,
2024-03-26 11:47:11 +08:00
async onBackendFail ( response , instance ) {
const authStore = useAuthStore ( ) ;
function handleLogout() {
authStore . resetStore ( ) ;
}
function logoutAndCleanup() {
handleLogout ( ) ;
window . removeEventListener ( 'beforeunload' , handleLogout ) ;
}
// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
const logoutCodes = import . meta . env . VITE_SERVICE_LOGOUT_CODES ? . split ( ',' ) || [ ] ;
2024-03-28 16:22:18 +08:00
if ( logoutCodes . includes ( response . data . status . toString ( ) ) ) {
2024-03-26 11:47:11 +08:00
handleLogout ( ) ;
return null ;
}
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import . meta . env . VITE_SERVICE_MODAL_LOGOUT_CODES ? . split ( ',' ) || [ ] ;
2024-03-28 16:22:18 +08:00
if ( modalLogoutCodes . includes ( response . data . status . toString ( ) ) ) {
2024-03-26 11:47:11 +08:00
// prevent the user from refreshing the page
window . addEventListener ( 'beforeunload' , handleLogout ) ;
2024-03-28 16:22:18 +08:00
// prevent repeated pop-ups
if ( ! request . state . isLogout ) {
request . state . isLogout = true ;
window . $dialog ? . error ( {
title : 'Error' ,
content : response.data.message ,
positiveText : $t ( 'common.confirm' ) ,
maskClosable : false ,
onPositiveClick() {
request . state . isLogout = false ;
logoutAndCleanup ( ) ;
} ,
onClose() {
request . state . isLogout = false ;
logoutAndCleanup ( ) ;
}
} ) ;
}
2024-03-26 11:47:11 +08:00
return null ;
}
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
const expiredTokenCodes = import . meta . env . VITE_SERVICE_EXPIRED_TOKEN_CODES ? . split ( ',' ) || [ ] ;
2024-03-28 16:22:18 +08:00
if ( expiredTokenCodes . includes ( response . data . status . toString ( ) ) && ! request . state . isRefreshingToken ) {
2024-03-26 11:47:11 +08:00
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 ;
2024-03-08 17:59:45 +08:00
} ,
transformBackendResponse ( response ) {
2024-03-30 17:07:04 +08:00
return response . data . total ? response.data : response.data.data ;
2024-03-08 17:59:45 +08:00
} ,
onError ( error ) {
// when the request is fail, you can show error message
let message = error . message ;
2024-03-26 11:47:11 +08:00
let backendErrorCode = '' ;
2024-03-08 17:59:45 +08:00
2024-03-26 11:47:11 +08:00
// get backend error message and code
2024-03-08 17:59:45 +08:00
if ( error . code === BACKEND_ERROR_CODE ) {
2024-03-21 11:53:27 +08:00
message = error . response ? . data ? . message || message ;
2024-03-28 16:22:18 +08:00
backendErrorCode = error . response ? . data ? . status . toString ( ) || '' ;
2024-03-26 11:47:11 +08:00
}
// the error message is displayed in the modal
const modalLogoutCodes = import . meta . env . VITE_SERVICE_MODAL_LOGOUT_CODES ? . split ( ',' ) || [ ] ;
if ( modalLogoutCodes . includes ( backendErrorCode ) ) {
return ;
}
// when the token is expired, refresh token and retry request, so no need to show error message
const expiredTokenCodes = import . meta . env . VITE_SERVICE_EXPIRED_TOKEN_CODES ? . split ( ',' ) || [ ] ;
if ( expiredTokenCodes . includes ( backendErrorCode ) ) {
return ;
2024-03-08 17:59:45 +08:00
}
2024-03-26 11:47:11 +08:00
window . $message ? . error ? . ( message ) ;
2024-03-08 17:59:45 +08:00
}
}
) ;
export const demoRequest = createRequest < App.Service.DemoResponse > (
{
2024-03-21 10:57:53 +08:00
baseURL : otherBaseURL.demo
2024-03-08 17:59:45 +08:00
} ,
{
async onRequest ( config ) {
const { headers } = config ;
// set token
const token = localStg . get ( 'token' ) ;
const Authorization = token ? ` Bearer ${ token } ` : null ;
Object . assign ( headers , { Authorization } ) ;
return config ;
} ,
isBackendSuccess ( response ) {
2024-03-21 10:57:53 +08:00
// when the backend response code is "200", it means the request is success
2024-03-08 17:59:45 +08:00
// you can change this logic by yourself
return response . data . status === '200' ;
} ,
async onBackendFail ( _response ) {
2024-03-21 10:57:53 +08:00
// when the backend response code is not "200", it means the request is fail
// for example: the token is expired, refresh token and retry request
2024-03-08 17:59:45 +08:00
} ,
transformBackendResponse ( response ) {
return response . data . result ;
} ,
onError ( error ) {
// when the request is fail, you can show error message
let message = error . message ;
// show backend error message
if ( error . code === BACKEND_ERROR_CODE ) {
2024-03-21 10:57:53 +08:00
message = error . response ? . data ? . message || message ;
2024-03-08 17:59:45 +08:00
}
window . $message ? . error ( message ) ;
}
}
) ;