如何使用反应路由器 V4 从 axios 拦截器重定向? [英] How to redirect from axios interceptor with react Router V4?
问题描述
我想在收到 403 错误时在 axios 拦截器中进行重定向.但是如何访问 React 组件之外的历史记录?
在 在 React-Router v4 中以编程方式导航 中,它位于上下文中一个 React 组件,但我在 axios 上下文中尝试
axios.interceptors.response.use(function (response) {//对响应数据做一些事情返回响应;}, 函数(错误){//做一些有响应错误的事情if(error.response.status === 403) { console.log("需要重定向!");}//Trow errr 再次(可能需要其他一些捕获)返回 Promise.reject(error);});
我通过从组件树外部访问我的 Redux Store 并从注销按钮向它发送我的相同操作来解决这个问题,因为我的拦截器是在单独的文件中创建的并在加载任何组件之前加载.
所以,基本上,我做了以下事情:
在 index.js
文件中:
//.... 为简洁起见省略了大量导入import { createStore, applyMiddleware } from 'redux';从redux-thunk"导入 reduxThunk;从'./reducers'导入reducers;从 './actions/types' 导入 { UNAUTH_USER };//这只是一个动作类型的常量文件.const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);const store = createStoreWithMiddleware(reducers);//这是我设置拦截器的家伙!NetworkService.setupInterceptors(store);//又省略了很多代码...//请注意下面的RequireAuth",后面会讲ReactDOM.render(<提供者商店={商店}><浏览器路由器><div><标题/><main className="plan-container"><开关><路由精确路径="/" component={Landing}/><路由精确路径="/login" component={Login}/><路由精确路径="/signup" component={Signup}/><路由精确路径="/calendar" component={RequireAuth(Calendar)}/><路由精确路径="/profile" component={RequireAuth(Profile)}/></开关></main>
</BrowserRouter></提供者>, document.querySelector('.main-container'));
在 network-service.js
文件中:
从'axios'导入axios;从 '../actions/types' 导入 { UNAUTH_USER };导出默认{setupInterceptors: (store) =>{//添加响应拦截器axios.interceptors.response.use(函数(响应){返回响应;}, 函数(错误){//如果会话结束则捕获!如果(error.response.data.token.KEY == 'ERR_EXPIRED_TOKEN'){console.log("过期令牌!");localStorage.clear();store.dispatch({ type: UNAUTH_USER });}返回 Promise.reject(error);});}};
最后,但并非最不重要的是,我有一个 HOC(高阶组件),我将受保护的组件包装在其中,当会话结束时我会在其中执行实际的重定向.这样,当我触发操作类型 UNAUTH_USER 时,它会将我的 session
减速器中的 isLogged
属性设置为 false
,因此该组件会收到通知并随时为我重定向.
require-auth.js
组件的文件:
import React, { Component } from 'react';从'react-redux'导入{连接};导出默认函数(组合组件){类 RequireAuth 扩展组件 {componentWillMount() {如果(!this.props.session.isLogged){this.props.history.push('/登录');}};componentWillUpdate(nextProps) {如果(!nextProps.session.isLogged){this.props.history.push('/登录');}};使成为() {return <ComposedComponent {...this.props}/>}}函数 mapStateToProps(state) {返回 { 会话:state.session };}返回连接(mapStateToProps)(RequireAuth);}
希望有帮助!
I want to make a redirection in axios interceptors when receiving a 403 error. But how can I access the history outside React components ?
In Navigating Programatically in React-Router v4, it's in the context of a React Component, but here i'm trying in axios context
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);
});
I solved that by accessing my Redux Store from outside the Component tree and sending it my same action from the logout button, since my interceptors are created in a separated file and loaded before any Component is loaded.
So, basically, I did the following:
At index.js
file:
//....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'));
And at the network-service.js
file:
import axios from 'axios';
import { UNAUTH_USER } from '../actions/types';
export default {
setupInterceptors: (store) => {
// Add a response interceptor
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
//catches if the session ended!
if ( error.response.data.token.KEY == 'ERR_EXPIRED_TOKEN') {
console.log("EXPIRED TOKEN!");
localStorage.clear();
store.dispatch({ type: UNAUTH_USER });
}
return Promise.reject(error);
});
}
};
Last, but not least, I have a HOC (Higher Order Component) that I wrap my protected components where I do the actual redirect when the session is out. That way, when I trigger the action type UNAUTH_USER, it sets my isLogged
property at my session
reducer to false
and therefore this component gets notified and does the redirect for me, at any time.
The file for require-auth.js
component:
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);
}
Hope that helps!
这篇关于如何使用反应路由器 V4 从 axios 拦截器重定向?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!