Reactjs 如何使用react路由器V4从axios拦截器重定向?

Reactjs 如何使用react路由器V4从axios拦截器重定向?,reactjs,react-router,axios,Reactjs,React Router,Axios,我想在收到403错误时在axios拦截器中进行重定向。但是如何访问React组件之外的历史记录 在中,它是在一个React组件的上下文中,但在这里我尝试在axios上下文中 axios.interceptors.response.use(function (response) { // Do something with response data return response; }, function (error) { // Do something with

我想在收到403错误时在axios拦截器中进行重定向。但是如何访问React组件之外的历史记录

在中,它是在一个React组件的上下文中,但在这里我尝试在axios上下文中

axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    if(error.response.status === 403) { console.log("Redirection needed !"); }

    // Trow errr again (may be need for some other catch)
    return Promise.reject(error);
});

我找到的最佳解决方案是在我的主要React组件中定义axios.interceptors,并使用
来处理错误:
(和路由器V4的
和路由器


我通过从组件树外部访问我的Redux存储并从注销按钮发送相同的操作来解决这个问题,因为我的拦截器是在一个单独的文件中创建的,并在加载任何组件之前加载

因此,基本上,我做了以下工作:

index.js
文件中:

//....lots of imports ommited for brevity
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import reducers from './reducers';
import { UNAUTH_USER } from './actions/types'; //this is just a constants file for action types.

const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
const store = createStoreWithMiddleware(reducers);

//Here is the guy where I set up the interceptors!
NetworkService.setupInterceptors(store);

//lots of code ommited again...
//Please pay attention to the "RequireAuth" below, we'll talk about it later

ReactDOM.render(
  <Provider store={store}>
      <BrowserRouter>
          <div>
              <Header />
              <main className="plan-container">
                  <Switch>
                      <Route exact path="/" component={Landing} />
                      <Route exact path="/login" component={Login} />
                      <Route exact path="/signup" component={Signup} />
                      <Route exact path="/calendar" component={RequireAuth(Calendar)} />
                      <Route exact path="/profile" component={RequireAuth(Profile)} />
                  </Switch>
              </main>
          </div>
      </BrowserRouter>
  </Provider>
  , document.querySelector('.main-container'));
最后,但并非最不重要的一点是,我有一个HOC(高阶组件),我将受保护的组件包装在其中,在会话结束时执行实际重定向。这样,当我触发操作类型UNAUTH_USER时,它会将我的
会话中的
isloged
属性设置为
false
,因此该组件会得到通知,并随时为我重定向

需要auth.js
组件的文件:

import React, { Component } from 'react';
import { connect } from 'react-redux';

export default function(ComposedComponent) {

    class RequireAuth extends Component {

        componentWillMount() {
            if(!this.props.session.isLogged) {
                this.props.history.push('/login');
            }
        };

        componentWillUpdate(nextProps) {
            if(!nextProps.session.isLogged) {
                this.props.history.push('/login');
            }
        };

        render() {
            return <ComposedComponent {...this.props} />
        }
    }

    function mapStateToProps(state) {
        return { session: state.session };
    }

    return connect(mapStateToProps)(RequireAuth);
}
import React,{Component}来自'React';
从'react redux'导入{connect};
导出默认函数(ComposedComponent){
类RequireAuth扩展组件{
组件willmount(){
如果(!this.props.session.isloged){
this.props.history.push('/login');
}
};
组件将更新(下一步){
如果(!nextrops.session.isloged){
this.props.history.push('/login');
}
};
render(){
返回
}
}
函数MapStateTops(状态){
返回{session:state.session};
}
返回连接(MapStateTops)(需要授权);
}

希望有帮助

我正在使用react router dom,它有“历史”道具,可用于向新路由的过渡

 history.push('/newRoute')

我通过从
history
()包创建浏览器历史记录并将其传递到拦截器函数中,然后从中调用
.push()
方法来解决此任务

主文件代码(其中的一部分):

拦截器配置:

import axios from 'axios';

export default {
  setupInterceptors: (store, history) => {

      axios.interceptors.response.use(response => {
        return response;
      }, error => {

      if (error.response.status === 401) {
        store.dispatch(logoutUser());
      }

      if (error.response.status === 404) {
         history.push('/not-found');
      }

      return Promise.reject(error);
    });
  },
};
另外,您应该使用
react Router
()中的
Router
,并传递与
history
param相同的历史对象

// app.js
...
ReactDOM.render(
  <Provider store={store}>
     <Router history={history}>
        ...
     </Router>
  </Provider>
, document.getElementById('#root'))
//app.js
...
ReactDOM.render(
...
,document.getElementById('#root'))

这似乎对我有用

 function (error) {
            var accessDenied = error.toString().indexOf("401");
            if (accessDenied !== -1) {
              console.log('ACCESS DENIED')
              return window.location.href = '/accessdenied'
            }
          });

公认的答案解决不了我的问题。在axios上花了一段时间,并在拦截器周围使用了一些罚单,但没有触发拦截器,我发现axios不支持像上面所描述的那样对拦截器进行全局修饰。对于未来的读者,请记住,axios已将此
全局拦截器
标记为功能。所以也许我们将来会得到它。参考:

对于所有api调用,我都有一个axios实例,所以我解决了在其中定义拦截器的问题

import { createHashHistory } from 'history' // or createBrowserHistory
const history = createHashHistory()

if (response.status === 403) {
  history.push('/login')
}

这非常有效

window.location.href = `${process.env.REACT_APP_BASE_HREF}/login`;

尝试使用以下代码:
从'react router'导入{browserHistory}
then
browserHistory.push(“/path”)尝试从'react router dom'导入{browserHistory}然后
浏览历史。推(“/path”)
但它不起作用,这是V3的方式,不是吗?是的,不幸的是,这似乎不适用于V4路由器…首先,这是一个伟大的解决方案与HOC!但是,您不想在
componentdiddupdate
中检查下一个更新的会话道具,而不是
componentWillUpdate
?@w3bshark当我在
componentWillUpdate
componentWillMount
中检查它时,我实际上是在避免会话丢失时重新渲染组件。如果我在
组件diddupdate
中找到它,它将首先被渲染,然后检查会话是否应该在那里,在我看来,这是一个安全漏洞和错误的设计。我很难理解您的解决方案。拦截器没有添加到您将要导出的任何axios实例中,那么您如何使用拦截器发出api请求呢?我想您没有公开
window.axios
。看起来您需要以某种方式导出带有拦截器的axios实例,但我看不出这将在哪里发生。据我所知,axios在导入时就像一个单例,因此只要您在某个点调用拦截器,它就会应用到整个应用程序,在库的同一个实例上。我不是使用redux,而是使用React上下文来管理应用程序状态。我不确定是否有办法从外部调用用户上下文。有任何提示/建议吗?在本例中,您用来进行API调用的代码是什么样子的,即您导入什么来进行请求?@maciejgurbin我简单导入axios库,并使用
get
post
等,如通常所见,那么您将如何测试这些拦截器呢?谢谢,mate,这取决于组件初始化顺序,如果某个组件在安装拦截器之前发出axios请求,则不会工作。
 function (error) {
            var accessDenied = error.toString().indexOf("401");
            if (accessDenied !== -1) {
              console.log('ACCESS DENIED')
              return window.location.href = '/accessdenied'
            }
          });
import { createHashHistory } from 'history' // or createBrowserHistory
const history = createHashHistory()

if (response.status === 403) {
  history.push('/login')
}

window.location.href = `${process.env.REACT_APP_BASE_HREF}/login`;