reactjs - 如何在刷新访问 token 时暂停和重新启动react-redux应用程序中的API调用?

标签 reactjs redux oauth-2.0 react-redux redux-saga

我们有一个react-redux应用程序,它在每次页面加载时使用多个API调用来获取数据。该应用程序遵循 OAuth2 协议(protocol)。它有一个经常过期的访问 token 和一个用于获取新访问 token 的刷新 token 。 如果使用过期的访问 token 进行 API 调用,则会收到 401 错误,并显示错误消息“API token 已过期”。然后我们需要从身份验证服务器获取新的 token 。

我的问题是这样的: 当页面加载时,假设调度了 8 个 API 调用。我们收到 3 个成功的 200,但从第 4 个响应开始,我们收到 401“API token 已过期”。此时,我想将所有已发出但未收到响应或收到 401 错误的 API 调用放入队列中,直到刷新访问 token 。成功刷新访问 token 后,我想重新执行队列中保存的 API 调用。我怎样才能实现这个目标?

在网上寻找这个,我发现 redux-saga 可能有效,但没有看到任何迹象表明它可以用于此用例。

最佳答案

我也曾经处理过这种情况。这是我的解决方案:

/**
 * 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
 */

这样,只有第一个请求才会真正创建新的访问 token ,其余请求将暂时停止,直到创建新的访问 token 。

关于reactjs - 如何在刷新访问 token 时暂停和重新启动react-redux应用程序中的API调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52409635/

相关文章:

reactjs - React 上下文中的 Next.js 是什么?

css - (React-redux frontend developer) 我应该使用 css 还是添加另一个框架?

javascript - Using Redux.createStore with Immutable 抛出“reducer is not a function”(How to use Redux with Immutable.js ans composeEnhancers)

javascript - React + Redux 组件更新后做一些事情

node.js - 应用程序部署到 Heroku 时找不到 Webpack

reactjs - react /Redux : how to hold login fail

react-router - 使用 React Redux Router,我应该如何访问路由的状态?

ruby-on-rails - rails api 和 node.js 应用程序之间的用户身份验证

c# - Paypal API 登录停止工作

ruby-on-rails - 使用 Ember.js 和 Torii (oauth2) 连接到 github