如何处理Redux / React应用程序中的401错误

时间:2017-01-22 21:57:26

标签: reactjs redux

我正在使用React和Redux构建一个站点,我有一个关于如何处理401状态响应的查询。

目前,当API报告401 HTTP状态时,通常会在我的某个操作中捕获它并发送:

return dispatch({
    type: 'FETCH_MONTHLY_DATA_FAILURE',
    error: response.data
});

相关的reducer检查HTTP状态代码,我有一些Redux中间件检查这个HTTPStatus状态值并做出相应的反应。

我能以更优雅的方式处理这些错误吗?我正在使用Axios来处理我的HTTP请求。

2 个答案:

答案 0 :(得分:8)

你说:

  

相关的reducer检查HTTP状态代码......

使用中间件很棒,但 reducer不应该检查http状态。这将超出其目的。

来自documentation

  

reducer作业是指定应用程序状态的变化方式   响应。

您的动作创建者应该是纯粹的,所有异步代码都应该存在于其他地方。

副作用不属于reducer

有很多方法可以做到这一点。这一切都归结为偏好。

以下是以更优雅的方式处理HTTP请求的3种方法:

选项1(最强大的一个):生成器,Sagas和异步操作的复杂链

redux-saga允许你这样做。我个人使用这个中间件来处理我的api调用和响应。

  

心理模型是一个传奇就像你的单独一个线程   专门负责副作用的应用程序。 redux-saga是   一个redux中间件,这意味着这个线程可以启动,暂停和   它具有正常的redux动作从主应用程序中取消   访问完整的redux应用程序状态,它可以发送redux   行动也是如此。

以下是使用此选项带来的好处:

  • 将副作用代码隔离到应用程序的单个域(sagas)
  • 多种传奇的构成(与承诺复合)
  • 减少承诺样板操作
  • 创作者纯粹更容易测试!

简化用例的实现,如:

  • 在大型多用户,多部门博客中,如果用户曾经有过 点击“订阅RSS Feed”按钮,然后下一次 用户访问具有专用RSS提要的部分,向他/她显示a 建议订阅此部分的Feed。

  • 在在线IDE中,如果用户从未使用过某个特定功能 申请,但已到达上述状态 功能可能有用,显示帮助对话框介绍 这个功能。

  • 在stackoverflow中,当用户回答问题时, OP已更改问题,因此您通知用户 问题已经改变,答案可能不再存在 有效的。

redux-observable是另一种选择:

撰写和取消异步操作以创建副作用等。

选项2:在操作创建者中将驱动异步操作的智能放在应用程序操作中

redux-promiseredux-thunk是很好的例子。

到目前为止一切顺利。我们删除了耦合,将异步逻辑分离到其他地方,并拥有一个干净的架构。但是,redux-saga更高级的功能将简化复杂的用例。

这是redux thunk的要点:

  

像redux-thunk或redux-promise这样的异步中间件包装了   store的dispatch()方法,允许你发送其他东西   比行动,例如,功能或承诺。任何中间件你   然后,使用可以解释你发送的任何东西,反过来,可以通过   对链中下一个中间件的操作。例如,一个承诺   中间件可以拦截Promises并发送一对开始/结束   响应每个Promise的异步动作。

选项3:通过高阶组件管理副作用

高阶组件(HOC)是JavaScript函数,它为现有组件类添加功能。正如React组件允许您向应用程序添加功能一样,高阶组件允许您向组件添加功能。你可以说它们是组件的组件。

Not ideal for all use cases !

例如:axios,一个基于promise的HTTP客户端,用于浏览器和node.js

选项4:生成器和承诺,没有Sagas

最后但并非最不重要的是,如果您不需要某些高级功能,您仍然可以使用生成器来管理前端的异步控制流,而无需添加redux-thunk依赖项。

答案 1 :(得分:6)

添加全局响应拦截器,在发生错误时调度操作

import store from './store';

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
}, function (error) {
    // Do something with response error
    store.dispatch({
        type: 'API_ERROR',
        payload: error,
    })
    return Promise.reject(error);
});

// In you reducers...
reduce(state, action) {
    if (action.type === 'API_ERROR' && action.payload.statusCode === 401) {
        return { // whatever needed }
    }
    return state;
}