programing

Axios 인터셉터가 원래 요청을 재시도하도록 하려면 어떻게 해야 합니까?

copysource 2022. 9. 1. 00:14
반응형

Axios 인터셉터가 원래 요청을 재시도하도록 하려면 어떻게 해야 합니까?

vue.js 응용 프로그램에 토큰 새로고침을 구현하려고 합니다.이것은 401 응답으로 스토어의 토큰을 리프레시하기 때문에 지금까지는 동작하고 있습니다만, 그 후에 인터셉터가 원래의 요구를 재시도하도록 하기만 하면 됩니다.

main.discloss.main.discloss.

axios.interceptors.response.use(
    response => {
        return response;
    },
    error => {
        console.log("original request", error.config);
        if (error.response.status === 401 && error.response.statusText === "Unauthorized") {
            store.dispatch("authRefresh")
                .then(res => {
                    //retry original request???
                })
                .catch(err => {
                    //take user to login page
                    this.router.push("/");
                });
        }
    }
);

store.displaces를 설정합니다.

authRefresh(context) {
    return new Promise((resolve, reject) => {
        axios.get("auth/refresh", context.getters.getHeaders)
            .then(response => {
                //set new token in state and storage
                context.commit("addNewToken", response.data.data);
                resolve(response);
            })
            .catch(error => {
                reject(error);
            });
    });
},

로그할 수 있습니다.error.config콘솔에서 원래 요청을 볼 수 있지만 원래 요청을 다시 시도하려면 여기서 무엇을 해야 하는지 아는 사람이 있습니까?또, 실패했을 경우, 반복해 루프 하는 것을 막습니다.

아니면 제가 완전히 잘못하고 있는 건가요?건설적인 비평은 환영한다.

다음과 같은 작업을 수행할 수 있습니다.

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

  const originalRequest = error.config;

  if (error.response.status === 401 && !originalRequest._retry) {

    originalRequest._retry = true;

    const refreshToken = window.localStorage.getItem('refreshToken');
    return axios.post('http://localhost:8000/auth/refresh', { refreshToken })
      .then(({data}) => {
        window.localStorage.setItem('token', data.token);
        window.localStorage.setItem('refreshToken', data.refreshToken);
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
        originalRequest.headers['Authorization'] = 'Bearer ' + data.token;
        return axios(originalRequest);
      });
  }

  return Promise.reject(error);
});

@Patel Pratik에 의해 제안된 구현은 양호하지만 한번에 하나의 요청만 처리합니다.

여러 요청의 경우 단순히axios-auth-refresh패키지.매뉴얼에 기재된 바와 같이:

플러그인은 새 인증 토큰을 기다리는 동안 수신된 추가 요청을 중지하고 새 토큰을 사용할 수 있는 경우 해결합니다.

https://www.npmjs.com/package/axios-auth-refresh

패키지를 추가하지 않고 동시에 실행되는 여러 요구에 대응하기 위해 @Patel Praik의 답변을 기반으로 합니다.

죄송합니다. 저는 Vue를 모릅니다.React를 사용하고 있습니다만, 논리를 번역해 주셨으면 합니다.

토큰 새로 고침 프로세스가 이미 진행 중인지 여부를 추적하는 상태 변수를 만들었습니다.토큰이 갱신되어 있는 동안 클라이언트로부터 새로운 요구가 있었을 경우, 새로운 토큰이 수신될 때까지(또는 새로운 토큰의 취득에 실패할 때까지) sleep 루프 상태로 유지합니다.수신 후 이러한 요청의 sleep 루프를 해제하고 업데이트된 토큰을 사용하여 원래 요청을 재시도합니다.

const refreshingTokens = useRef(false) // variable to track if new tokens have already been requested

const sleep = ms => new Promise(r => setTimeout(r, ms));

axios.interceptors.response.use(function (response) {
    return response;
}, async (error) => {
    const originalRequest = error.config;
    if (error.response.status === 401 && !originalRequest._retry) {
        originalRequest._retry = true;

        // if the app is not already requesting a new token, request new token
        // i.e This is the path that the first request that receives status 401 takes
        if (!refreshingTokens.current) {
            refreshingTokens.current = true //update tracking state to say we are fething new tokens
            const refreshToken = localStorage.getItem('refresh_token')
            try {
                const newTokens = await anAxiosInstanceWithoutInterceptor.post(`${process.env.REACT_APP_API_URL}/user/token-refresh/`, {"refresh": refreshToken});
                localStorage.setItem('access_token', newTokens.data.access);
                localStorage.setItem('refresh_token', newTokens.data.refresh);
                axios.defaults.headers['Authorization'] = "JWT " + newTokens.data.access
                originalRequest.headers['Authorization'] = "JWT " + newTokens.data.access
            refreshingTokens.current = false //update tracking state to say new 
                return axios(originalRequest)
            } catch (e) {
                await deleteTokens()
                setLoggedIn(false)
            }
            refreshingTokens.current = false //update tracking state to say new tokens request has finished
        // if the app is already requesting a new token
        // i.e This is the path the remaining requests which were made at the same time as the first take
        } else {
            // while we are still waiting for the token request to finish, sleep for half a second 
            while (refreshingTokens.current === true) {
                console.log('sleeping')
                await sleep(500);
            }
            originalRequest.headers['Authorization'] = "JWT " + 
            localStorage.getItem('access_token');
            return axios(originalRequest)
        }
    }
    return Promise.reject(error);
});

while loop을 사용하지 않을 경우 여러 요청 구성을 상태 변수 배열에 푸시하고 새 토큰 프로세스가 완료될 때 이벤트 청취자를 추가한 다음 저장된 모든 배열을 다시 시도할 수 있습니다.

언급URL : https://stackoverflow.com/questions/58395577/how-can-i-get-an-axios-interceptor-to-retry-the-original-request

반응형