403エラーを受け取った場合、axiosインターセプターでリダイレクトを行いたいです。しかし、どのようにReact components外の履歴にアクセスできますか?
React-Router v4でプログラム的にナビゲートする では、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);
});
コンポーネントツリーの外部から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'));
そしてnetwork-service.js
ファイルで:
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);
});
}
};
最後に大事なことを言い忘れましたが、セッションが切れたときに実際のリダイレクトを行う保護されたコンポーネントをラップするHOC(高次コンポーネント)があります。そのようにして、アクションタイプUNAUTH_USERをトリガーすると、isLogged
レデューサーのsession
プロパティがfalse
に設定されるため、このコンポーネントは通知を受け、リダイレクトを行います。いつでも。
require-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);
}
お役に立てば幸いです!
history
( https://github.com/ReactTraining/history )パッケージからブラウザー履歴を作成し、インターセプター関数に渡して.Push()
それからメソッド。
メインファイルコード(その一部):
// app.js
import createHistory from 'history/createBrowserHistory';
import httpService from './api_client/interceptors';
...
const history = createHistory();
httpService.setupInterceptors(store, history);
インターセプターの構成:
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
を使用して( https://github.com/ReactTraining/react-router )、history
と同じ履歴オブジェクトを渡す必要がありますパラメータ.
// app.js
...
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
...
</Router>
</Provider>
, document.getElementById('#root'))
お役に立てれば!
私が見つけた最良の解決策は、メインのReactコンポーネント内でaxios.interceptorsを定義し、that
を使用してエラーを処理することです:(ルーターV4からのwithRouter
を使用)
import {withRouter} from 'react-router-dom';
class Homepage extends Component {
static propTypes = {
history: PropTypes.object.isRequired
}
constructor(props){
super(props);
let that = this;
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) { that.handle403() }
// Trow errr again (may be need for some other catch)
return Promise.reject(error);
});
}
handle403(){
this.props.history.Push('/login');
}
これは私のために働くようです
function (error) {
var accessDenied = error.toString().indexOf("401");
if (accessDenied !== -1) {
console.log('ACCESS DENIED')
return window.location.href = '/accessdenied'
}
});
反応ルーターdomを使用していますが、新しいルートへの移行に使用できる「履歴」プロップがあります
history.Push('/newRoute')
受け入れられた答えは私の問題を解決しません。 axiosとインターセプター周辺のチケットでトリガーをかけないで時間を費やした後、axiosはインターセプターを上記のようにグローバルに装飾することをサポートしていません。今後の読者のために、axiosがこのglobal interceptor
機能として。将来的には入手できるかもしれません。 ref: https://github.com/axios/axios/issues/99 。
すべてのapi呼び出しに対して単一のaxiosインスタンスがあるため、インターセプターを定義することを解決しました。
import { createHashHistory } from 'history' // or createBrowserHistory
const history = createHashHistory()
if (response.status === 403) {
history.Push('/login')
}