diff --git a/src/api/email.api.ts b/src/api/email.api.ts index b391580..7fbbb22 100644 --- a/src/api/email.api.ts +++ b/src/api/email.api.ts @@ -1,6 +1,22 @@ -import axios from '@/utils/axios' -import { EmailSendDto, EmailSendResponse } from './email.interface' +import { authAxios, normalAxios } from '@/utils/axios' +import { + EmailSendDto, + EmailSendResponse, + EmailVerifyCodeScene, +} from './email.interface' export async function sendEmailVerifyCode(params: EmailSendDto) { - return axios.get('/api/email/verifyCode', { params }) + if ( + [ + EmailVerifyCodeScene.register, + EmailVerifyCodeScene.forgetPassword, + ].includes(params.scene) + ) { + return normalAxios.get('/api/email/verifyCode', { + params, + }) + } + return authAxios.get('/api/email/verifyCode', { + params, + }) } diff --git a/src/api/user.api.ts b/src/api/user.api.ts index abae9d1..5e9545f 100644 --- a/src/api/user.api.ts +++ b/src/api/user.api.ts @@ -1,5 +1,4 @@ -import axios from '@/utils/axios' -import { type AxiosResponse } from 'axios' +import { authAxios, normalAxios } from '@/utils/axios' import { LoginInputDto, RegisterInputDto, @@ -10,35 +9,25 @@ import { } from './user.interface' export async function register(data: RegisterInputDto) { - return axios.post('/api/users', data) + return normalAxios.post('/api/users', data) } export async function login(data: LoginInputDto) { - return axios.post('/api/users/token', data) -} - -export async function logout() { - return axios.delete('/api/users/me/token') + return normalAxios.post('/api/users/token', data) } export async function forgetPassword(data: ForgetPasswordInputDto) { - return axios.patch('/api/users/password', data) + return normalAxios.patch('/api/users/password', data) +} + +export async function logout() { + return authAxios.delete('/api/users/me/token') } export async function deleteUser(data: DeleteUser) { - return axios.delete('/api/users/me', { data }) -} - -let refreshing: Promise> | null -export async function refreshToken() { - if (!refreshing) { - refreshing = axios.put('/api/users/me/token').finally(() => { - refreshing = null - }) - } - return refreshing + return authAxios.delete('/api/users/me', { data }) } export async function getUserInfo() { - return axios.get('/api/users/me') + return authAxios.get('/api/users/me') } diff --git a/src/utils/axios.ts b/src/utils/axios.ts deleted file mode 100644 index 5dff12a..0000000 --- a/src/utils/axios.ts +++ /dev/null @@ -1,55 +0,0 @@ -import axios, { type AxiosError } from 'axios' -import Router from 'next/router' -import status from 'http-status' -import * as api from '@/api' -import { toast } from 'react-toastify' - -interface ErrorResponse { - statusCode: number - message: string -} - -const throwError = (error: AxiosError) => { - toast.error( - error.response?.data.message.toString() ?? error.response?.statusText, - ) - return Promise.reject(error) -} - -axios.interceptors.request.use(function (config) { - const accessToken = localStorage.getItem('accessToken') - config.headers.Authorization = `Bearer ${accessToken}` - return config -}) - -axios.interceptors.response.use( - function (response) { - return response - }, - async function (error: AxiosError) { - // fail to refresh token - if ( - error.config && - error.config.url === '/api/users/me/token' && - error.config.method === 'put' - ) { - Router.push('/login') - return throwError(error) - } - switch (error.response?.status) { - case status.UNAUTHORIZED: { - if (error.config?.url === '/api/users/token') { - throw throwError(error) - } - const res = await api.user.refreshToken() - localStorage.setItem('accessToken', res.data) - return error.config && axios.request(error.config) - } - default: { - return throwError(error) - } - } - }, -) - -export default axios diff --git a/src/utils/axios/authAxios.ts b/src/utils/axios/authAxios.ts new file mode 100644 index 0000000..1155fd7 --- /dev/null +++ b/src/utils/axios/authAxios.ts @@ -0,0 +1,53 @@ +import axios, { AxiosError, type AxiosResponse } from 'axios' +import Router from 'next/router' +import status from 'http-status' +import { AccessToken } from '@/api/user.interface' +import { throwError, ErrorResponse } from './throwError' +import normalAxios from './normalAxios' + +/** 需要Authorization的axios */ +const authAxios = axios.create() + +authAxios.interceptors.request.use(function (config) { + const accessToken = localStorage.getItem('accessToken') + config.headers.Authorization = `Bearer ${accessToken}` + return config +}) + +authAxios.interceptors.response.use( + (response) => response, + async (error: AxiosError) => { + switch (error.response?.status) { + case status.UNAUTHORIZED: { + const res = await refreshToken() + localStorage.setItem('accessToken', res.data) + return error.config && axios.request(error.config) + } + default: { + return throwError(error) + } + } + }, +) + +const refreshToken = (() => { + let refreshingToken: Promise> | null = null + return async function () { + if (!refreshingToken) { + refreshingToken = normalAxios + .put('/api/users/me/token') + .finally(() => { + refreshingToken = null + }) + } + refreshingToken?.catch((error) => { + if (error instanceof AxiosError) { + Router.push('/login') + throwError(error) + } + }) + return refreshingToken + } +})() + +export default authAxios diff --git a/src/utils/axios/index.ts b/src/utils/axios/index.ts new file mode 100644 index 0000000..fe228b6 --- /dev/null +++ b/src/utils/axios/index.ts @@ -0,0 +1,4 @@ +import authAxios from './authAxios' +import normalAxios from './normalAxios' + +export { authAxios, normalAxios } diff --git a/src/utils/axios/normalAxios.ts b/src/utils/axios/normalAxios.ts new file mode 100644 index 0000000..a1adcc3 --- /dev/null +++ b/src/utils/axios/normalAxios.ts @@ -0,0 +1,17 @@ +import axios, { AxiosError } from 'axios' +import { throwError, ErrorResponse } from './throwError' + +const normalAxios = axios.create() + +normalAxios.interceptors.response.use( + (response) => response, + async (error: AxiosError) => { + switch (error.response?.status) { + default: { + return throwError(error) + } + } + }, +) + +export default normalAxios diff --git a/src/utils/axios/throwError.ts b/src/utils/axios/throwError.ts new file mode 100644 index 0000000..fde8af5 --- /dev/null +++ b/src/utils/axios/throwError.ts @@ -0,0 +1,14 @@ +import { AxiosError } from 'axios' +import { toast } from 'react-toastify' + +export interface ErrorResponse { + statusCode: number + message: string +} + +export const throwError = (error: AxiosError) => { + toast.error( + error.response?.data.message.toString() ?? error.response?.statusText, + ) + return Promise.reject(error) +}