mitmitwiki

axios interceptors로 401 error 처리

kohi ☕ 2023. 4. 2. 02:16

처리 내용

1. 유저 로그인 시 액세스 토큰과 리프레시 토큰을 발급한다. 액세스 토큰은 클라이언트에서 store 변수에 담아 관리하고 리프레시 토큰은 서버에서 httpOnly 쿠키에 저장하도록 처리한다.

2. API 요청 시 액세스 토큰을 검증한다.

3. 액세스 토큰이 만료된 경우 401 error ▶ token refresh 요청 액세스 토큰 발급

4. 새로 발급된 토큰으로 재요청한다.

 

axios interceptors

axios interceptors는 then이나 catch로 처리되기 전에 요청(request)나 응답(response)을 가로채 어떠한 작업을 수행할 수 있게 한다.

// 요청 쌔벼서 가공
customAxios.interceptors.request.use(
    (config) => {
        return config;
    },
    (error) => {
        return Promise.reject(error);
    }
);

// 응답 쌔벼서 가공
customAxios.interceptors.response.use(
    (response) => {
        return response;
    },

    (error) => {
        return Promise.reject(error);
    }
);

 

작성한 코드

customAxios.interceptors.response.use(
    (response) => {
        const res = response.data;
        return res;
    },

    async (error) => {
        const err = error as AxiosError;
        
        // 401 error일 때
        if (err.response?.status === 401) {
            const data = err.response.data;
            
            // 토큰 재발급 요청
            const user = store.getState().user;
            const { token } = await reissueToken(user.id);
            
            // store 갱신
            store.dispatch(
                setLogin({
                    token: `bearer ${token}`,
                    id: user.id,
                    account: user.account,
                })
            );
            
            // 헤더에 담긴 토큰 값 변경
            err.config.headers = {
                "Content-Type": "application/json",
                Authorization: `bearer ${token}`,
            };
            
            // 재요청
            const originalResponse = await axios.request(error.config);
            return originalResponse.data;
            
            // 405 error일 때 (리프레시 토큰 만료)
        } else if (err.response?.status === 405) {
            alert("로그아웃 되었습니다.");
            
            // store 초기화
            store.dispatch(
                setLogin({
                    token: "",
                    id: 0,
                    account: null,
                })
            );
        }
        return Promise.reject(error);
    }
);