이챙의 개발 log
axios interceptors로 서버랑 JWT 토큰 주고받기
✨interceptor✨
요청이 전송되기전, 응답이 처리되기전 실행되는 함수.
즉 요청을 할때 헤더를 바꾸거나 응답이 처리되기전 무언가 에러처리를 바꾼다거나 데이터를 바꿀 수 있는 미들웨어 역할을 한다.
그래..그래서 요청 전에 뭘 어떻게 한다는건데..
axios.interceptors.request 로 요청 전 처리
axios.interceptors.request.use(
(config) => {
// 요청전에 토큰을 처리
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
},
(error) => {
// 에러 처리
return Promise.reject(error);
}
);
요청이 전송되기 전 config객체를 받아서 headers.Authorization을 수정한다. 이때 토큰을 넣으면 된다.
서버에 요청되기전에 실행되는 함수이기 때문에 토큰이 있는지 없는지 확인을 하는 로직을 수행후 config를 리턴하면 함수가 실행된다.
axios.interceptors.response 로 응답 오류 처리
axios.interceptors.response.use(
(response) => {
// 응답이 성공일 경우 로직 처리
return response.data;
},
(error) => {
// 에러 처리
return Promise.reject(error);
}
);
axios.interceptors.request에서 요청을 하고 응답이 오면 axios.interceptors.response의 response에서 응답 객체를 받는다.
만약 서버에서 보낸 응답이 오류이면 error함수에서 에러에 대한 응답을 받는다.
이쯤 개념을 조금 익히면 토큰을 어떻게 서버에 전달해야 겠다 감이 잡힘.
1. axios 인스턴스를 생성한다.
export const axiosAuth = axios.create({
baseURL: BASE_URL,
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
});
create메서드를 사용해서 axios인스턴스를 생성할 수 있다.
동일한 요청을 하나의 인스턴스로 관리해서 전역적으로 관리 할 수 있다.
withCredentials 옵션은 cors처리 때문에 해줘야 하는데 서로 다른 도메인일 경우 쿠키가 전송되지 않기때문에 true로 설정 해주었고, 사용자의 정보를 Authorization에 넣어 보내기 때문에 credential한 정보를 담는 경우 이 옵션 처리를 해줘야 된다고 함.
2. 인터셉터로 요청 전 토큰(token) 처리
axiosAuth.interceptors.request.use(
config => {
const copyConfig = { ...config };
if (!config.headers) return config;
const accessToken = localStorage.getItem(ACCESS_TOKEN);
if (accessToken && config.headers) {
// access token을 header에 담아 요청
copyConfig.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
},
error => {
console.log(error);
return Promise.reject(error);
}
);
http 요청이 되기전 로컬스토리지에 보관한 access token을 꺼내서 헤더에 담아 요청으로 보냈다.
3. access token이 만료될 경우 refresh token으로 재요청
axiosAuth.interceptors.response.use(
response => response,
async error => {
console.log(error);
const errorStatus = error.response.status;
const originalRequest = error.config;
const refreshToken = getCookie(REFRESH_TOKEN);
// refresh token을 body에 넣어 -> access token 재발급
if (errorStatus === 401) {
try {
const res = await axiosDefault.post('/members/reissue', {
refreshToken
});
const newAccessToken = res.data.tokenResponse.accessToken;
const newRefreshToken = res.data.tokenResponse.refreshToken;
localStorage.setItem(ACCESS_TOKEN, newAccessToken);
setCookie(REFRESH_TOKEN, newRefreshToken, {
path: '/'
});
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
return await axios(originalRequest);
} catch (err) {
alert('토큰 재발급에 실패했습니다. 다시 로그인 해주세요');
window.location.replace('/auth');
}
}
// 에러 반환.
return Promise.reject(error);
}
);
만약 위에서 요청전에 보낸 accesstoken이 만료됬을 경우 응답 에러가 401로 떨어진다.
401일 경우 분기처리를 해서 쿠키에 보관해놨던 리프레시 토큰을 꺼내서 다시 서버로 요청한다.
새로운 acceesstoken을 재발급 받게 되면 headers.Authorization을 재수정한다. 그리고 이전 api 요청을 재시도한다.
이 로직으로 수행이 잘 되면 axios 인터셉터로 토큰을 관리하면서 서버에 요청/응답을 할 수 있다.
나 같은 경우에는 토큰 재발급에 실패할경우 다시 로그인을 유도 하기위해 로그인 페이지로 리다이렉트 처리를 해주었다.
특히 리프레시 토큰 할때 500에러랑 무한루프 현상을 겪어서 코드 정리하는데 애를 좀 먹었따;
500에러는 백엔드쪽에서 api 명세서랑 다르게 요청처리를 적어놔서 였고 무한루프는 await 처리를 안해서 났었던듯..
👍🏻인터셉터의 효과
HTTP요청을 전역에서 관리가 가능하여 코드의 재사용성과 유지보수 측면에서 탁월하다. 공통된 요청이 있을경우 axios 인터셉터를 활용하자!!!
'회고록 > 일정 프로젝트' 카테고리의 다른 글
로그인시 접근 가능한 라우팅 구현(react guard route) (0) | 2024.06.18 |
---|---|
React SSE 실시간 알림 구현하기 (0) | 2024.02.20 |
제로베이스 팀프로젝트 5주차~데모데이까지 후기 (2) | 2024.01.30 |
CORS 에러에 대해서.. 상황마다 해결 방법이 다르다! (1) | 2024.01.15 |
제로베이스 프론트엔드 스쿨 팀프로젝트 4주차 후기 (1) | 2024.01.12 |
이챙(leechaeng)
프론트엔드 개발도 하고 뛰기도 하고