axios interceptor는 HTTP 요청과 응답을 가로채서 처리할 수 있는 기능이다
interceptor의 특징 중 하나는 요청과 응답을 가로채기 때문에 공통적으로 중복되는 코드들을 줄일 수 있다는 장점이 있다
api 요청에 대해 일괄적으로 처리할 수 있어서 코드의 유지 보수성을 높일 수 있다
const customAxios = axios.create({
baseURL: 'http://localhost:8080',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
사용자 지정 config로 새로운 axios 인스턴스를 만들 수 있다
instance를 썼을 때 장점은 api를 호출하는 과정에서 반복되는 코드 baseURL, timeout, headers와 같은 코드들을 줄일 수 있다
customAxios.request.use(
function (config) {
// 요청을 보내기 전에 수행할 일
return config;
},
function (error) {
// 오류 요청을 보내기전 수행할 일
return Promise.reject(error);
});
request는 server에 요청을 보내기 전에 실행된다
customAxios.response.use(function (response) {
// 응답 데이터가 있는 작업 수행
return response;
}, function (error) {
// 응답 오류가 있는 작업 수행
return Promise.reject(error);
});
response는 서버로부터의 응답을 받은 후 실행된다
그럼 interceptor를 사용해서 refreshToken을 활용한 jwt 토큰 관리를 해보자
우선 jwt에 대해 알아야 한다 jwt를 모른다면 이것을 읽고 오자
customAxios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const { status, code, message } = error.response.data;
if (message) {
if (status === 401 && code === 'EXPIRED_TOKEN') {
tokenExpired();
}
}
return Promise.reject(error);
},
);
서버에서 401과 EXPIRED_TOKEN을 던져주면 tokenExpired를 불러와 refreshToken을 이용해서 accessToken을 재발급할 것이다
import { customAxios } from 'lib/axios/customAxios';
import { ACCESS_KEY, REFRESH_KEY } from 'constants/token.constant';
export const tokenExpired = async () => {
try {
const { data } = await customAxios.put('/auth', null, {
headers: {
'Refresh-Token':
`${localStorage.getItem(REFRESH_KEY)}`,
},
});
localStorage.setItem(ACCESS_KEY, data.accessToken);
} catch (err) {
useErrorToast('세션이 만료되었습니다');
}
};
toeknExpired에서는 서버에게 재발급 요청을 headers에 refreshToken을 집어넣어 보내주고
서버는 정상적인 refreshToken이라면 accessToken을 줄 것이다
그리고 우리는 새로운 accessToken을 storage에 저장함으로써 로그인 수명을 연장할 수 있게 된다
import axios from 'axios';
import { tokenExpired } from 'lib/token/tokenExpired';
const customAxios = axios.create({
baseURL: 'http://localhost:8080',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
customAxios.interceptors.request.use(
(config) => {
return config;
},
(error) => {
return Promise.reject(error);
},
);
customAxios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const { status, code, message } = error.response.data;
if (message) {
if (status === 401 && code === 'EXPIRED_TOKEN') {
tokenExpired();
}
}
return Promise.reject(error);
},
);
export { customAxios };
import { customAxios } from 'lib/axios/customAxios';
import { ACCESS_KEY, REFRESH_KEY } from 'constants/token.constant';
export const tokenExpired = async () => {
try {
const { data } = await customAxios.put('/auth', null, {
headers: {
'Refresh-Token':
`${localStorage.getItem(REFRESH_KEY)}`,
},
});
localStorage.setItem(ACCESS_KEY, data.accessToken);
} catch (err) {
useErrorToast('세션이 만료되었습니다');
}
};
https://axios-http.com/kr/docs/interceptors
https://axios-http.com/kr/docs/instance