Kimsora✨
article thumbnail
320x100
반응형

프로젝트 유지보수 해야지 하다가 한달만에 ....  여러 수많은 에러를 겪었는데 적지 않아 기억이 나지 않는다

 

 

📌기본세팅

const api = axios.create({
  baseURL: process.env.REACT_APP_API_URL, 
  headers: {
    "content-type": "application/json",
  },
  withCredentials: true,
});

바로 에러  프로젝트에서 content-type을 두가지 사용해야 되서 두가지 적용을 해야하기 때문에 따로 빼야했다 ㅎㅎ

 const instance = axios.create({
    baseURL: process.env.REACT_APP_API_URL,
    withCredentials: true,
  });

 

 

📌axios.interceptors.request.use를 사용하여 모든 HTTP 요청을 가로채기

instance.interceptors.request.use(
    async (config) => {
      if (accessToken && !config.headers["Authorization"]) {
        if (config.data instanceof FormData) {
          config.headers["Content-Type"] = "multipart/form-data";
        } else {
          config.headers["Content-Type"] = "application/json";
        }
        config.headers["Authorization"] = `Bearer ${accessToken}`;
        dispatch(
          login({
            accessToken,
            memberId,
            isLogin: true,
            expire,
            refreshToken,
          })
        );
      }
      return config;
    },
    (error) => {
      Promise.reject(error);
    }
  );

여기서 config는  매개변수는 HTTP 요청 구성(config) 객체이다

여기에서 content-type을 정해주었다

꼭 리턴해주기 return config 
=>수정된 요청 구성(config) 객체를 반환하여 해당 요청이 수정된 설정으로 실행되도록 하는 역할

 

instanceof는 자바스크립트에서 객체의 타입을 확인하는 연산자=>특정 객체가 특정 클래스의 인스턴스인지 아닌지를 검사하여 불리언 값을 반환한다

object instanceof constructor
object :테스트할 개체.
constructor:테스트할 생성자
 

📌response interceptor에서는 HTTP 응답 객체를 검사하고, 만료된 토큰에 대한 처리를 수행 =>로그인 연장 처리하기

 

현재시간과 로컬스토리지에 저장되어있는 expire시간을 비교해 자동로그인 하는 로직을 추가했다

만약 이 조건이 참이라면, 서버에 새로운 토큰을 요청하여 토큰을 갱신해서 로그인 해야하는데 404에러뜨고 안돼서 

콘솔로 찍으니 새로받은 토큰은 잘들어 왔지만 로그인 연장은 안돼서 한참 헤맸다 🥲

요청 객체의 구성(config)을 수정하지 않기 때문에 원래 요청 객체에 대한 정보가 손실될 가능성이 있다고 한다

instance.interceptors.response.use(
    function (response) {
      return response;
    },

    async function (error) {
      if (isLogin && Date.now() >= expire) {
        try {
          const headers = {
            "Content-Type": "application/json",
            Authorization: `Bearer ${accessToken}`,
            refreshtoken: `Bearer ${refreshToken}`,
          };

          const data = await axios({
            url: `${process.env.REACT_APP_API_URL}/api/members/${memberId}`,
            method: "GET",
            headers,
          });
          console.log(data.headers);
          const { refreshtoken: newRefreshToken, authorization } = data.headers; // refreshToken 변수 이름 변경
          dispatch(
            login({
              accessToken: authorization,
              memberId,
              isLogin: true,
              expire: Date.now() + 1000 * 60 * 60,
              refreshToken: newRefreshToken,
            })
          );
          return instance.request(error.config); 
        } catch (error) {
         ..////
        }
      }

      return Promise.reject(error);
    }
  );

 

 

 

수정되지 않은 채로 원래의 요청을 보내게 되기 때문에 새로운 객체를 만들어주고 다시  Axios에 그객체를 넣어주고 리턴 해줘야한다
=> 수정된 newConfig 객체를 사용하여 Axios 요청을 다시 보내야한다

훅으로 만들었기 때문에  return instance해 주어야 한다

=>createAPIWithAuth 함수에서 생성한 인증 정보를 추가한 Axios 인스턴스를 리턴함으로써, 해당 인스턴스를 사용하는 쪽에서 인증 정보가 추가된 Axios 인스턴스를 이용하여 HTTP 요청을 보낼 수 있게 된다

   //error.config.headers.Authorization = `Bearer ${authorization}`;
  // error.config.headers.refreshtoken = `Bearer ${newRefreshToken}`;
const newConfig = { ...error.config };
        newConfig.headers.Authorization = `Bearer ${authorization}`;
        newConfig.headers.refreshtoken = `Bearer ${newRefreshToken}`;
        return await axios(newConfig);

 

  instance.interceptors.response.use(
    function (response) {
      return response;
    },

    async function (error) {
      const { config, response } = error;
      console.log(config);
      console.log(response);
      if (isLogin && Date.now() >= expire) {
        try {
          const headers = {
            "Content-Type": "application/json",
            Authorization: `Bearer ${accessToken}`,
            refreshtoken: `Bearer ${refreshToken}`,
          };

          const data = await axios({
            url: `${process.env.REACT_APP_API_URL}/api/members/${memberId}`,
            method: "GET",
            headers,
          });
          const { refreshtoken: newRefreshToken, authorization } = data.headers; // refreshToken 변수 이름 변경
          dispatch(
            login({
              accessToken: authorization,
              memberId,
              isLogin: true,
              expire: Date.now() + 1000 * 60 * 60,
              refreshToken: newRefreshToken,
            })
          );
          const newConfig = { ...error.config };
          newConfig.headers.Authorization = `Bearer ${authorization}`;
          newConfig.headers.refreshtoken = `Bearer ${newRefreshToken}`;
          return axios(newConfig);
        } catch (error) {
          dispatch(
            logout({
              accessToken: null,
              memberId: null,
              isLogin: false,
              refreshToken: refreshToken,
            })
          );
          const headers = {
            "Content-Type": "application/json",
            Authorization: `Bearer ${accessToken}`,
            refreshToken: `Bearer ${refreshToken}`,
          };
          await axios({
            url: `${process.env.REACT_APP_API_URL}/api/members/logout`,
            method: "POST",
            headers,
          });
          localStorage.clear();
          window.location.href = "/login";
          window.location.reload();
        }
      }
      return Promise.reject(error);
    }
  );

  return instance;
};

axios 인스턴스를 만드는 대신에, 기존의 axios 에서 로그아웃 처리를 해주기

=> 새로운 axios 인스턴스를 만드는 오버헤드를 줄이고, 코드의 일관성을 유지할 수 있다

 

 

인터셉터를 사용하면 한결더 간결해지고 한곳에서 에러핸드링하기 좋다

느낀점:어렵다.. 실제적용하기 어렵다 우선은 되는데 제대로 된코드 인지 모르겠다... 간편하라고 만들었는데 일일히 토큰추가 하는게 인터셉터 적용하는것보다 수십배는 빠를것같닿ㅎ

728x90
반응형
profile

Kimsora✨

@sorarar

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그

WH