axios - interceptors

이진화행·2022년 3월 3일
0

Parkjin

목록 보기
13/14

1. axios - interceptors

axios interceptors는?

axios interceptors는 then,또는 catch 로 처리되기전에 request 나 response로 어떠한 작업을 수행할수있게한다.

// 요청 (request) interceptor
axios.interceptors.request.use(
	function(config){
    	//요청을 보내기전에 수행할 작업
        return config
    }
    funtion(error){
    	//오류 요청 가공
        return Promise.reject(error);
    }
);

//응답 (response) interceptor
axios.interceptros.response.use(
	function(response){
    	// 200대 response를 받아 응답 데이터를 가공하는 작업
         return response;
    }
    function(error){
    	// 200대 이외의 오류 응답을 가공
        return Promise.reject(error)
    }
)

axios.interceptors 는 보통 토큰값을 리프레시할때 많이사용된다.

error response에 대한 interceptor 작성

요청에 대한 응답이 401 Error인 경우, refreshToken을 가지고 Token Refresh api 호출해야 하므로 error response에 대한 interceptor를 작성한다.

axios.interceptors.response.use(
  (response) => {
    return response;
  },
  async (error) => {
    const {
      config,
      response: { status },
    } = error;
    if (status === 401) {
      if (error.response.data.message === "TokenExpiredError") {
        const originalRequest = config;
        const refreshToken = await AsyncStorage.getItem("refreshToken");
        // token refresh 요청
        const { data } = await axios.post(
          `http://localhost:3000/refresh/token`, // token refresh api
          {
            refreshToken,
          }
        );
        // 새로운 토큰 저장
        const {
          accessToken: newAccessToken,
          refreshToken: newRefreshToken,
        } = data;
        await AsyncStorage.multiSet([
          ["accessToken", newAccessToken],
          ["refreshToken", newRefreshToken],
        ]);
        axios.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`;
        originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
        // 401로 요청 실패했던 요청 새로운 accessToken으로 재요청
        return axios(originalRequest);
      }
    }
    return Promise.reject(error);
  }
);

이런식으로 작성하게되면 토큰 만료시, 토큰을 재발급을 받아 요청을 다시보내는것 까지는 가능하다. 그러나 여러가지 요청이 동시에 들어오게되면 토큰이 여러번 발급되게 되어 오류가 발생된다.
이러한 문제를 해결하기 위하여 토큰이 재발급 되는 동안 다른 요청들은 서버에 보내지 않고 모아 두어, 새로운 토큰 발급이 완료된 후에 한꺼번에 요청하는 코드를 추가해야한다.

let isTokenRefreshing = false;
let refreshSubscribers = [];

const onTokenRefreshed = (accessToken) => {
  refreshSubscribers.map((callback) => callback(accessToken));
};

const addRefreshSubscriber = (callback) => {
  refreshSubscribers.push(callback);
};

axios.interceptors.response.use(
  (response) => {
    return response;
  },
  async (error) => {
    const {
      config,
      response: { status },
    } = error;
    const originalRequest = config;
    if (status === 401) {
      if (!isTokenRefreshing) {
        // isTokenRefreshing이 false인 경우에만 token refresh 요청
        isTokenRefreshing = true;
        const refreshToken = await AsyncStorage.getItem("refreshToken");
        const { data } = await axios.post(
          `http://localhost:3000/refresh/token`, // token refresh api
          {
            refreshToken,
          }
        );
        // 새로운 토큰 저장
        const {
          accessToken: newAccessToken,
          refreshToken: newRefreshToken,
        } = data;
        await AsyncStorage.multiSet([
          ["accessToken", newAccessToken],
          ["refreshToken", newRefreshToken],
        ]);
        isTokenRefreshing = false;
        axios.defaults.headers.common.Authorization = `Bearer ${newAccessToken}`;
        // 새로운 토큰으로 지연되었던 요청 진행
        onTokenRefreshed(newAccessToken);
      }
      // token이 재발급 되는 동안의 요청은 refreshSubscribers에 저장
      const retryOriginalRequest = new Promise((resolve) => {
        addRefreshSubscriber((accessToken) => {
          originalRequest.headers.Authorization = "Bearer " + accessToken;
          resolve(axios(originalRequest));
        });
      });
      return retryOriginalRequest;
    }
    return Promise.reject(error);
  }
);

출처:https://maruzzing.github.io/study/rnative/axios-interceptors로-토큰-리프레시-하기/

profile
기술블로그

0개의 댓글