프로젝트에서 로그인 기능처럼 AccessToken이 필요없는 요청을 제외하고 대부분의 요청에 대해 AccessToken을 Header에 담아 보내야했다. 이를 위해 axiosInstance를 따로 만들어서 사용하는 방법을 사용했었다.
const 토큰넣은Instance = axios.create({
baseURL: process.env.SERVER_URL,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken('accessToken')}`,
},
});
const 토큰없는Instance = axios.create({
baseURL: process.env.SERVER_URL,
headers: {
'Content-Type': 'application/json',
},
});
위 코드처럼 인스턴스를 하나 더 만들었고, 토큰에 대한 수정 사항이 생기면 인스턴스를 갈아끼우는 불편한 경험을 했다. 이를 해결하기 위해 Interceptor를 활용해 서버로 가는 요청에 토큰을 넣어주는 방식으로 수정했다.
인터셉터는 클라이언트와 서버 사이에서 요청을 가로채서 중간에 처리를 하는 역할을 한다.
request와 response 두 상황 모두 적용할 수 있으며 구성은 아래와 같다.
axios.interceptors.request.use(
function (config) {
// 요청을 보내기 전에 수행할 작업
return config;
},
function (error) {
// 요청을 보내기 전 에러가 발생했을 때 수행할 작업
return Promise.reject(error);
}
);
const axiosInstance = axios.create({
baseURL: process.env.SERVER_URL
});
addAccessToken
함수를 만들어준다.// config는 request보내기 전 수정가능한 객체
const addAccessToken = (config) => {
const accessToken = localStorage.getItem('AccessToken');
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
};
axiosInstance.interceptors.request.use(addAccessToken, (err) => {
return Promise.reject(err);
});
이렇게 인터셉터를 통해 API 요청이 서버로 도달하기 전에 요청을 가로채 특정 요구사항을 처리할 수 있다.
현재 프로젝트의 서버에서는 Access token이 만료되면 401에러를 리턴해준다. 만약 Access token이 만료되어 refresh token으로 갱신해줘야하는 상황이라면, response에 대한 Interceptor로 에러발생 시 갱신 요청을 수행할 수 있다.
const handleRefreshToken = async (error) => {
if (!error.response || error.response.status !== 401) return Promise.reject(error);
const originalRequest = error.config;
try {
// 토큰 갱신 요청 보내기
const newTokens = await refreshAccessToken();
// 갱신받은 access 토큰 저장
localStorage.setItem('Authorization', newTokens.Authorization);
// 새 토큰으로 헤더 수정
originalRequest.headers.Authorization = `Bearer ${newTokens.Authorization}`;
// 재요청
return axiosInstance(originalRequest);
} catch (refreshError) {
alert('인증이 만료되었습니다. 다시 로그인해주세요');
// 로그인 페이지로 이동
return Promise.reject(refreshError);
}
};
axiosInstance.interceptors.response.use((response) => response, handelRefreshToken);
간략하게 표현하면 위 코드 순서대로 동작하게 된다.