1. 상황
api를 일부러 다른 경로를 작성했더니 위 이미지와 같이 무한대로 api요청을 한다. 이는 서버에게 심각한 부하를 가져다 줄 수 있다. 살펴보면, 재발급 api와 데이터를 받아오는 api 두 개를 반복하고 있다.
2. 문제 해결
axios interceptors에서, 계속 요청하고 있는게 아닐까?
이게 가장 유력한 원인이라 생각했다.
지금 privateApi.interceptor.response는 다음과 같다.
privateApi.interceptors.response.use(
(response: AxiosResponse) => {
return response.data;
},
async (error: AxiosError<ErrorType, InternalAxiosRequestConfig>) => {
try{
// 각 상황별 에러 처리
}
}catch (e) {
return Promise.reject(e);
}
}
);
try를 하다가 throw문을 실행하면, catch(e)가 받아서, reject한다.
try 내부는 다음과 같다.
if (!error.response) return Promise.reject(error);
만약 error.response가 없다면, reject한다. 이 때, 이 문이 어차피 try-catch문 안에 있기 때문에 throw를 해도, catch가 받아서 reject할 것이다. 이 때 여기서 reject하는 것이 맞을까, throw하는 것이 맞을까?
throw를 하여 try .. catch문에서 한 번에 모아서 reject하는 것도 좋지만, 더 명시적으로 작성하기 위해서는 각 문에서 에러를 throw하는 것이 더 적절하다고 판단하였다.
if (
error.response.status === AUTH_ERROR_CODES.UNAUTHORIZED ||
error.response.status === AUTH_ERROR_CODES.NOT_FOUND
) {
window.location.href = '/join?step=1';
}
토큰 에러라면, 회원가입 페이지로 이동시킨다. UNAUTHORIZED과 NOT_FOUND의 에러코드는 다음과 같다.
- UNAUTHORIZED: 401
- NOT_FOUND: 404
if (error.response.status === AUTH_ERROR_CODES.TOKEN_ERROR) {
// ..
}
토큰 재발급이 필요한 경우 서버에서 403을 내려주기에 토큰 재발급을 요청한다. 여기서 토큰 재발급 요청을 하고
const { refreshToken, accessToken } = await getTokenFromCookie();
const {
token: { accessToken: reIssuedAccessToken, refreshToken: reIssuedRefreshToken },
} = await postReissue(
{ accessToken, refreshToken },
{ headers: { 'X-AUTH-TOKEN': accessToken } }
);
쿠키에서 토큰을 가져와서, 재발급을 요청한다.
prevRequest.headers['X-AUTH-TOKEN'] = reIssuedAccessToken;
return privateApi(prevRequest);
그리고, 가져온 토큰으로 재요청을 한다.
이 때, 재요청을하고, api에 실패하면 토큰을 재발급하고, 또 기존 api를 요청 하고 .. 무한 반복이다.
왜 처음에 403에러가 도착했을까?
이 403에러 코드는 서버에서 보내주는 것이다. 없는 path에서 403으로 보내주도록 설정한 것이다.
해결 방법은 다음 두가지가 있다.
- 모든 403에러는 토큰 이슈일 때만 전송하도록 백엔드와 규칙을 통일한다.
- 이 방식도 물론 필요한 작업이라 생각한다.
- 프론트단에서, 토큰 검사를 다시 설계한다.
- 아무리 프론트와 백엔드가 에러 코드를 맞추어도, 프론트단에서도 처리가 필요하다고 생각한다.
- 현재, 토큰 검사는 middleware에서 하고 있다. middleware에서는 토큰 만료 기간이 지났는지 체크하여 지났다면, 재요청을 해서 토큰 세팅을 한다. 여기다가 axios interceptor에서도 체크를 해야할까? 불필요하다고 생각한다. 만약 토큰 만료기간이 지나지 않아서 토큰 에러가 발생했다면, 로그인 페이지로 이동하는 것이 맞다고 생각한다.
정리
axios.reponse.interceptor에서 발생한 이슈였다. 서버에서 403에러를 보내준다 > 토큰 재발급을 한다 > 토큰 재발급을 했으니 토큰 세팅을하여 api를 다시 요청한다 > 서버에서 403에러를 보내준다 … 무한 반복이 되는 것이었다.
서버에서 이 403에러가 아니라, 없는 path의 경우 404에러로 보내줄 것을 요청을 해야겠다. 그리고 프론트단에서도 이미 토큰 검사는 middleware에서 하므로 interceptor에서 다시 요청하는 로직은 제거해야겠다.