ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Axios Jwt RefreshToken 중복요청
    프로그래밍/Javascript 2024. 2. 4. 17:23
    반응형

    1. 문제

    Client는 모든 Axios 요청에 대해서 Access Token을 Header에 추가하여 요청을 진행합니다.

    만약 Access Token이 없거나 만료가 되었을 경우 Cookie에 저장되어 있는 Refresh Token을 이용하여 Access Token을 갱신받아 요청들을 다시 재요청하는 방법으로 구현되어 있습니다.

    Axios의 비동기 방식의 요청에서 문제가 발생하게 되었습니다. Access Token이 만료된 상태에서 Axios를 이용하여 3개의 요청을 보낼경우 Refresh Token 갱신 요청또한 3번이 발생하는 것입니다.

    2. 문제 순서도

    실재 동작하는 순서입니다. 우리가 생각한 순서는 1번요청을 하고 1번 요청에서 Access Token이 만료가 된다면 Refresh 토큰을 통해 Access Token을 갱신하고 그다음 2번 요청과 3번 요청을 진행하여 2번과 3번은 Refresh 요청없이 결과를 받아오는 과정을 생각하였을 것입니다.

    💡 혹시 위 순서도에서 1, 2, 3번 순서로 요청했는데 왜 응답은 1, 2, 3 순으로 응답이 오지 않지 할 수 있다. Axios는 비동기로 요청을 보내기 때문에 순서대로 요청을 보내도 Server에서 먼저 처리된 응답을 먼저 전달하여 응답 순서가 달라질 수 있습니다.

    3. 문제 해결 방법

    문제를 해결하는 방법은 많이있을 것 입니다. 그 중 저는 Memoize라는 Library를 이용하여 이 문제를 해결하고자 합니다.

    Memoize Library를 이용한 방법은 설정한 시간안에 같은 Function을 호출하면 Cache되어 있는 값을 반환하는 방식을 취할 수 있습니다.

     

    즉 1, 2, 3번 요청을 진행 2번요청이 가장 먼저 응답되어 Refresh 요청을 보내게 되면 1, 3번 요청은 동일 한 Refresh 요청을 하는 함수를 호출하지만 실제 요청에 대한 결과 값은 Cache된 값에서 전달 받게 되므로 Server로 요청은 진행하지 않게됩니다.

    4. 해결 과정

    npm을 통한 설치
    npm install memoize
    ----------------------
    yarn을 통한 설치
    yarn add memoize
    

    먼저 memoize를 설치 합니다.

    export let refreshToken = async () => {
      try{
    		// 토큰이 만료되어 갱신요청을 하는 부분
        return http.post('/refresh-token');
      } catch (e) {
    		// 오류 발생 시 필요한 조치 추가
      }
    }
    

    기존 Access Token을 갱신하기 위해 요청하는 부분의 함수입니다.

    export let memoizeRefreshToken = memoize(async () => {
      try{
    		// 토큰이 만료되어 갱신요청을 하는 부분
        return http.post('/refresh-token');
      } catch (e) {
        // 오류 발생 시 필요한 조치 추가
      }
    }, {maxAge: 1000});
    

    이걸 memoize를 통해 함수 결과 Cache가 가능하도록 변경하였습니다. 2번째 파라미터의 maxAge는 해당 함수의 Cache되는 시간을 설정하는 것으로 예시에는 1초로 설정하였습니다.

    instance.interceptors.response.use(
      (response) => {
        return response;
      },
      async (error) => {
        if(error.response.status !== 401){
          //401이 아닌경우 Axios Reject
    			return Promise.reject(error);
    		}
    		
    		await memoizeRefreshToken().then((result) => {
    			// 특정 저장소에 accessToken 저장
    	    localStorage.setItem('accessToken', result.accessToken);
    			// 재요청에는 신규로 발급 받은 AccessToken이 추가
          error.config.headers['Authorization'] = 'Bearer ' + result.accessToken;
        });
    
    		// 401로 응답받은 요청에 대한 재요청을 시도
        return instance.request(error.config);
      });
    

    이번에는 Access Token의 갱신 요청을 하는 부분을 확인 해보겠습니다. Axios의 Interceptor를 이용하여 Error에 대한 응답을 Interceptor합니다. 그리고 Error Code가 401인지 확인 401이 아니라면 Reject시키도록 구성되어 있습니다.

    401이라면 memoize가 되는 memoizeRefreshToken 함수를 호출합니다. 그리고 응답으로 받은 Access Token을 특정 저장소에 저장 시키고 재요청을 위해 Header에 Access Token을 추가합니다. 마지막으로 첫 요청에 대한 재요청을 진행하여 마무리하게 됩니다.

    5. 해결 결과

    위 요청 순서를 보면 최초 3개의 Axios 요청을 진행하였으며 3개 모두 401응답이 온 것을 확인 할 수 있습니다. 하지만 Access Token Refresh 요청은 딱 1번만 요청된 것을 확인할 수 있습니다. 이후 3개의 요청은 모두 신규로 발급받은 Access Token을 이용하여 재요청을 진행하였습니다.

     

    이것으로 Axios Jwt Refresh 중복 요청 해결 과정에 대한 설명을 마치도록 하겠습니다.

    반응형

    댓글

Designed by Tistory.