웹 개발을 하다 보면 서버와 통신할 때 반복적으로 처리해야 하는 공통 로직들이 생깁니다. 예를 들어 JWT 토큰을 모든 요청 헤더에 붙인다거나, 에러 응답을 일관되게 처리한다거나, 응답 데이터 구조를 통일한다거나 하는 일들이죠.
이때 유용하게 사용할 수 있는 기능이 바로 Axios Interceptor입니다.
📤 요청 인터셉터
// 모든 요청에 공통 로직 적용 axios.interceptors.request.use( (config) => { // 요청 시작 로그 console.log(`🚀 API 요청: ${config.method?.toUpperCase()}${config.url}`); // 인증 토큰 자동 추가 const token = localStorage.getItem('accessToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } // 요청 시간 기록 (성능 측정용) config.metadata = { startTime: newDate() }; return config; }, (error) => { console.error('❌ 요청 설정 오류:', error); returnPromise.reject(error); } );
📥 응답 인터셉터
// 모든 응답에 공통 로직 적용 axios.interceptors.response.use( (response) => { // 응답 시간 계산 const endTime = newDate(); const duration = endTime - response.config.metadata.startTime; console.log(`✅ API 응답: ${response.config.url} (${duration}ms)`); return response; }, async (error) => { const originalRequest = error.config; // 401 에러: 토큰 갱신 처리 if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const refreshToken = localStorage.getItem('refreshToken'); const response = await [axios.post](http://axios.post)('/auth/refresh', { refreshToken }); const newToken = [response.data](http://response.data).accessToken; localStorage.setItem('accessToken', newToken); // 원래 요청에 새 토큰 적용 후 재시도 originalRequest.headers.Authorization = `Bearer ${newToken}`; returnaxios(originalRequest); } catch (refreshError) { // 토큰 갱신 실패 시 로그인 페이지로 리다이렉트 localStorage.clear(); window.location.href = '/login'; } } // 에러 로깅 console.error('❌ API 에러:', { url: error.config?.url, status: error.response?.status, message: error.message }); returnPromise.reject(error); } );