| | |
| | | import axios from 'axios' |
| | | import { useUserStore } from '@/store/modules/user' |
| | | import { ApiStatus } from './status' |
| | | import { HttpError, handleError, showError, showSuccess } from './error' |
| | | import { HttpError, handleError, resolveRequestUrl, showError, showSuccess } from './error' |
| | | import { $t } from '@/locales' |
| | | const REQUEST_TIMEOUT = 30e3 |
| | | const LOGOUT_DELAY = 500 |
| | |
| | | ) |
| | | axiosInstance.interceptors.response.use( |
| | | (response) => { |
| | | if (!isStandardResponse(response.data)) { |
| | | throw createInvalidResponseError(response) |
| | | } |
| | | const { code, msg } = response.data |
| | | if (code === ApiStatus.success) return response |
| | | if (code === ApiStatus.unauthorized) handleUnauthorizedError(msg) |
| | | throw createHttpError(msg || $t('httpMsg.requestFailed'), code) |
| | | if (code === ApiStatus.unauthorized) handleUnauthorizedError(msg, response.config) |
| | | throw createHttpError( |
| | | msg || $t('httpMsg.requestFailed'), |
| | | code ?? ApiStatus.error, |
| | | createErrorOptions( |
| | | response.config, |
| | | { |
| | | data: response.data, |
| | | status: response.status, |
| | | contentType: response.headers?.['content-type'] |
| | | }, |
| | | response |
| | | ) |
| | | ) |
| | | }, |
| | | (error) => { |
| | | if (error.response?.status === ApiStatus.unauthorized) handleUnauthorizedError() |
| | | return Promise.reject(handleError(error)) |
| | | } |
| | | ) |
| | | function createHttpError(message, code) { |
| | | return new HttpError(message, code) |
| | | function createHttpError(message, code, options) { |
| | | return new HttpError(message, code, options) |
| | | } |
| | | function handleUnauthorizedError(message) { |
| | | const error = createHttpError(message || $t('httpMsg.unauthorized'), ApiStatus.unauthorized) |
| | | function handleUnauthorizedError(message, config) { |
| | | const error = createHttpError( |
| | | message || $t('httpMsg.unauthorized'), |
| | | ApiStatus.unauthorized, |
| | | createErrorOptions(config) |
| | | ) |
| | | if (!isUnauthorizedErrorShown) { |
| | | isUnauthorizedErrorShown = true |
| | | logOut() |
| | |
| | | ApiStatus.gatewayTimeout |
| | | ].includes(statusCode) |
| | | } |
| | | function createErrorOptions(config, extra = {}, response) { |
| | | return { |
| | | url: response?.request?.responseURL || resolveRequestUrl(config), |
| | | method: config?.method?.toUpperCase(), |
| | | ...extra |
| | | } |
| | | } |
| | | function isStandardResponse(payload) { |
| | | return payload !== null && typeof payload === 'object' && !Array.isArray(payload) && 'code' in payload |
| | | } |
| | | function createInvalidResponseError(response) { |
| | | const responseData = response?.data |
| | | const responseText = |
| | | typeof responseData === 'string' ? responseData.slice(0, 300) : responseData |
| | | const contentType = String(response?.headers?.['content-type'] || '') |
| | | const looksLikeHtml = |
| | | contentType.includes('text/html') || |
| | | (typeof responseData === 'string' && |
| | | /<(!doctype|html|head|body)\b/i.test(responseData.trim().slice(0, 120))) |
| | | const message = looksLikeHtml |
| | | ? $t('httpMsg.invalidHtmlResponse') |
| | | : $t('httpMsg.invalidResponseFormat') |
| | | return createHttpError( |
| | | message, |
| | | ApiStatus.error, |
| | | createErrorOptions( |
| | | response?.config, |
| | | { |
| | | data: responseText, |
| | | status: response?.status, |
| | | contentType |
| | | }, |
| | | response |
| | | ) |
| | | ) |
| | | } |
| | | async function retryRequest(config, retries = MAX_RETRIES) { |
| | | try { |
| | | return await request(config) |