Как приостанавливать и перезапускать вызовы API в приложении реагировать на избыточность при обновлении токена доступа? - PullRequest
0 голосов
/ 19 сентября 2018

У нас есть приложениеact-redux, которое извлекает данные с использованием нескольких вызовов API при каждой загрузке страницы.Приложение следует протоколу OAuth2.Он имеет токен доступа, который часто истекает, и токен обновления, который будет использоваться для получения нового токена доступа.Если вызов API выполняется с токеном с истекшим сроком действия, появляется сообщение об ошибке 401 с сообщением об ошибке «Срок действия токена API истек».Затем нам нужно получить новый токен с сервера аутентификации.

Моя проблема заключается в следующем: при загрузке страницы, скажем, было отправлено 8 вызовов API.Мы получаем 3 успешных 200-х, но начиная с 4-го ответа мы получаем 401 «Токен API истек».На этом этапе я хочу поместить все вызовы API, которые я уже сделал, но не получил ответ или получил ошибку 401, в очередь, пока я не обновлю маркер доступа.После успешного обновления токена доступа я хочу повторно выполнить вызовы API, сохраненные в очереди.Как мне этого добиться?

Когда я искал это в Интернете, я обнаружил, что redux-saga может работать, но не увидел никаких признаков того, что его можно использовать для этого варианта использования.

1 Ответ

0 голосов
/ 19 сентября 2018

Я также имел дело с этим делом.Это мое решение:

/**
 * Connect to API
 */
export const makeRequest = (args) => {
    const request = fetch(args)//example

    return _retryRequestIfExpired(request, args)
}


/**
 * Fake get access token.
 */
const _getNewAccessToken = () => {
    return new Promise((resolve, reject) => {
        resolve('xyz')
    })
}

const _retryRequestIfExpired = (request, args) => {
    return request.catch(error => {
        if (error === 'abc') {//Any reason you want
            return _refreshAccessToken()
                .then(newAccessToken => {
                    const updateArgs = {
                        ...args,
                        headers: {
                            'Authorization': newAccessToken
                        }
                    }

                    //Retry with new access token
                    return makeRequest(updateArgs)
                })
        }

        throw error
    })
}

/**
 * Important
 */
let _isRefreshingToken = false
let _subscribers = []

const _subscribe = subscriber => {
    if (typeof subscriber !== 'function' || _subscribers.indexOf(subscriber) !== -1) {
        return false
    }

    _subscribers = [].concat(_subscribers, [subscriber])
}

const _broadcast = (error = null, data) => {
    _isRefreshingToken = false

    _subscribers.forEach(subscriber => {
        subscriber(error, data)
    })

    _subscribers = []
}

const _refreshAccessToken = () => {
    if (_isRefreshingToken) {//If a request is creating new access token
        return new Promise((resolve, reject) => {
            const subscriber = (error, accessToken) => {
                if (error) {
                    return reject(error)
                }

                return resolve(accessToken)
            }

            _subscribe(subscriber)
        })
    }

    _isRefreshingToken = true

    return _getNewAccessToken()
        .then(accessToken => {
            _broadcast(null, accessToken)

            return accessToken
        })
        .catch(error => {
            _broadcast(error)

            throw error
        })
}
/**
 * End Important
 */

Таким образом, только первый запрос фактически создаст новый токен доступа, а оставшиеся запросы будут временно остановлены, пока не будет создан новый токен доступа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...