source

Axios 대행 수신자가 원래 요청을 재시도하고 원래 약속에 액세스합니다.

manysource 2023. 1. 27. 21:21

Axios 대행 수신자가 원래 요청을 재시도하고 원래 약속에 액세스합니다.

액세스 토큰의 유효기간이 지났을 경우 401개의 에러를 검출하기 위한 인터셉터가 준비되어 있습니다.기한이 만료되면 새 액세스 토큰을 얻기 위해 새로 고침 토큰을 시도합니다.이 시간 내에 다른 콜이 발신되면 액세스토큰이 검증될 때까지 큐잉됩니다.

이 모든 것이 잘 작동하고 있습니다.단, Axios(originalRequest)를 사용하여 큐를 처리할 때 원래 연결된 약속은 호출되지 않습니다.예에 대해서는, 이하를 참조해 주세요.

작동 중인 인터셉터 코드:

Axios.interceptors.response.use(
  response => response,
  (error) => {
    const status = error.response ? error.response.status : null
    const originalRequest = error.config

    if (status === 401) {
      if (!store.state.auth.isRefreshing) {
        store.dispatch('auth/refresh')
      }

      const retryOrigReq = store.dispatch('auth/subscribe', token => {
        originalRequest.headers['Authorization'] = 'Bearer ' + token
        Axios(originalRequest)
      })

      return retryOrigReq
    } else {
      return Promise.reject(error)
    }
  }
)

새로 고침 방법(새 액세스 토큰을 얻기 위해 새로 고침 토큰 사용)

refresh ({ commit }) {
  commit(types.REFRESHING, true)
  Vue.$http.post('/login/refresh', {
    refresh_token: store.getters['auth/refreshToken']
  }).then(response => {
    if (response.status === 401) {
      store.dispatch('auth/reset')
      store.dispatch('app/error', 'You have been logged out.')
    } else {
      commit(types.AUTH, {
        access_token: response.data.access_token,
        refresh_token: response.data.refresh_token
      })
      store.dispatch('auth/refreshed', response.data.access_token)
    }
  }).catch(() => {
    store.dispatch('auth/reset')
    store.dispatch('app/error', 'You have been logged out.')
  })
},

auth/actions 모듈에서 메서드를 구독합니다.

subscribe ({ commit }, request) {
  commit(types.SUBSCRIBEREFRESH, request)
  return request
},

또한 변환:

[SUBSCRIBEREFRESH] (state, request) {
  state.refreshSubscribers.push(request)
},

다음은 액션의 예를 제시하겠습니다.

Vue.$http.get('/users/' + rootState.auth.user.id + '/tasks').then(response => {
  if (response && response.data) {
    commit(types.NOTIFICATIONS, response.data || [])
  }
})

리프레시 토큰이 새로운 토큰에 액세스 할 필요가 있기 때문에 이 요구가 큐 I에 추가된 경우 원래 토큰을 첨부합니다().

  const retryOrigReq = store.dispatch('auth/subscribe', token => {
    originalRequest.headers['Authorization'] = 'Bearer ' + token
    // I would like to attache the original .then() as it contained critical functions to be called after the request was completed. Usually mutating a store etc...
    Axios(originalRequest).then(//if then present attache here)
  })

액세스 토큰이 갱신되면 요청 큐가 처리됩니다.

refreshed ({ commit }, token) {
  commit(types.REFRESHING, false)
  store.state.auth.refreshSubscribers.map(cb => cb(token))
  commit(types.CLEARSUBSCRIBERS)
},

2019년 2월 13일 갱신

많은 사람들이 이 토픽에 관심을 가지고 있기 때문에, 여기서 지정한 동작을 실현하는데 도움이 되는 axios-auth-refresh 패키지를 작성했습니다.


여기서 중요한 것은 올바른 Promise 객체를 반환하는 것입니다.이것에 의해, 다음의 조작을 실시할 수 있습니다..then()쇠사슬을 채인.Vuex의 상태를 사용할 수 있습니다.리프레시 콜이 발생했을 경우, 이 콜을refreshing에게 진술하다.true리프레시 콜을 보류 중인 콜로 설정할 수도 있습니다.이 방법:.then()는 항상 올바른 Promise 오브젝트에 바인드되며 Promise가 완료되면 실행됩니다.이렇게 하면 토큰의 재충전을 기다리는 콜을 유지하기 위해 추가 큐가 필요하지 않습니다.

function refreshToken(store) {
    if (store.state.auth.isRefreshing) {
        return store.state.auth.refreshingCall;
    }
    store.commit('auth/setRefreshingState', true);
    const refreshingCall = Axios.get('get token').then(({ data: { token } }) => {
        store.commit('auth/setToken', token)
        store.commit('auth/setRefreshingState', false);
        store.commit('auth/setRefreshingCall', undefined);
        return Promise.resolve(true);
    });
    store.commit('auth/setRefreshingCall', refreshingCall);
    return refreshingCall;
}

이렇게 하면 항상 이미 작성된 요구가 Promise로 반환되거나 새로운 요구가 생성되어 다른 콜에 대해 저장됩니다.이제 당신의 요격기는 다음과 비슷해 보일 것입니다.

Axios.interceptors.response.use(response => response, error => {
    const status = error.response ? error.response.status : null

    if (status === 401) {

        return refreshToken(store).then(_ => {
            error.config.headers['Authorization'] = 'Bearer ' + store.state.auth.token;
            error.config.baseURL = undefined;
            return Axios.request(error.config);
        });
    }

    return Promise.reject(error);
});

그러면 보류 중인 모든 요청을 다시 실행할 수 있습니다.하지만 어떤 질문도 없이 한 번에.


보류 중인 요구를 실제 호출된 순서대로 실행하려면 콜백을 두 번째 파라미터로refreshToken()기능을 합니다.

function refreshToken(store, cb) {
    if (store.state.auth.isRefreshing) {
        const chained = store.state.auth.refreshingCall.then(cb);
        store.commit('auth/setRefreshingCall', chained);
        return chained;
    }
    store.commit('auth/setRefreshingState', true);
    const refreshingCall = Axios.get('get token').then(({ data: { token } }) => {
        store.commit('auth/setToken', token)
        store.commit('auth/setRefreshingState', false);
        store.commit('auth/setRefreshingCall', undefined);
        return Promise.resolve(token);
    }).then(cb);
    store.commit('auth/setRefreshingCall', refreshingCall);
    return refreshingCall;
}

그리고 요격기:

Axios.interceptors.response.use(response => response, error => {
    const status = error.response ? error.response.status : null

    if (status === 401) {

        return refreshToken(store, _ => {
            error.config.headers['Authorization'] = 'Bearer ' + store.state.auth.token;
            error.config.baseURL = undefined;
            return Axios.request(error.config);
        });
    }

    return Promise.reject(error);
});

두 번째 예는 테스트하지 않았지만, 효과가 있거나 적어도 아이디어를 줄 수 있을 것입니다.

첫 번째 예제의 작업 데모 - 모의 요청과 사용된 서비스 데모 버전 때문에 시간이 좀 지나도 동작하지 않습니다만, 여전히 코드는 존재합니다.

출처: 대행 수신 - 대행 수신된 메시지가 오류로 해결되지 않도록 하는 방법

이것은, 1개의 대행 수신기로 실행할 수 있습니다.

let _refreshToken = '';
let _authorizing: Promise<void> | null = null;
const HEADER_NAME = 'Authorization';

axios.interceptors.response.use(undefined, async (error: AxiosError) => {
    if(error.response?.status !== 401) {
        return Promise.reject(error);
    }

    // create pending authorization
    _authorizing ??= (_refreshToken ? refresh : authorize)()
        .finally(() => _authorizing = null)
        .catch(error => Promise.reject(error));

    const originalRequestConfig = error.config;
    delete originalRequestConfig.headers[HEADER_NAME]; // use from defaults

    // delay original requests until authorization has been completed
    return _authorizing.then(() => axios.request(originalRequestConfig));
});

나머지는 애플리케이션 고유의 코드입니다.

  • api 로그인
  • 스토리지에서 인증 데이터 저장/로드
  • 토큰 새로 고침

전체 예를 확인하십시오.

왜 이런 걸 시도해 보지 않는 거죠?

서는 AX를 사용하고 있습니다.발신 방향은, 「」로 설정합니다.Authorization머리글는, AX)을 합니다.IOS(R)에 대응합니다.약속은 오류가 무엇이었는지 확인합니다. 401 이었고 처음 확인되었을 경우(즉, 재시도 내역이 아님) 토큰을 새로 고칩니다.을 사용법 같은 에는 ★★★★★★★★★★★★★★★★★★★★★★★.refreshToken()AWS Cognito를 사용하지만 자신에게 가장 적합한 것을 사용할 수 있습니다. 2번 이 두 개 있습니다.refreshToken():

  1. 되면 AX를합니다. 토큰과 Configuration )IOS " - " " "retryerrors로 API가 를 설정합니다.401 러 flag 、 401 에 、 flag flag flag flag flag 。요.resolve ★★★★★★★★★★★★★★★★★」rejectAXAX의 "에 대한 인수 되거나 거부되지 .IOS를 이용하지 않으면 새로운 약속은 해결되거나 거부되지 않습니다.

  2. 어떠한 이유로도 토큰을 갱신할 수 없는 경우 - 약속을 거부합니다.에러가 수 있기 .try/catchAWS Cognito


Vue.prototype.$axios = axios.create(
  {
    headers:
      {
        'Content-Type': 'application/json',
      },
    baseURL: process.env.API_URL
  }
);

Vue.prototype.$axios.interceptors.request.use(
  config =>
  {
    events.$emit('show_spin');
    let token = getTokenID();
    if(token && token.length) config.headers['Authorization'] = token;
    return config;
  },
  error =>
  {
    events.$emit('hide_spin');
    if (error.status === 401) VueRouter.push('/login'); // probably not needed
    else throw error;
  }
);

Vue.prototype.$axios.interceptors.response.use(
  response =>
  {
    events.$emit('hide_spin');
    return response;
  },
  error =>
  {
    events.$emit('hide_spin');
    return new Promise(function(resolve,reject)
    {
      if (error.config && error.response && error.response.status === 401 && !error.config.__isRetry)
      {
        myVue.refreshToken(function()
        {
          error.config.__isRetry = true;
          error.config.headers['Authorization'] = getTokenID();
          myVue.$axios(error.config).then(resolve,reject);
        },function(flag) // true = invalid session, false = something else
        {
          if(process.env.NODE_ENV === 'development') console.log('Could not refresh token');
          if(getUserID()) myVue.showFailed('Could not refresh the Authorization Token');
          reject(flag);
        });
      }
      else throw error;
    });
  }
); 

언급URL : https://stackoverflow.com/questions/51563821/axios-interceptors-retry-original-request-and-access-original-promise