it-swarm.com.de

Wie kann man von Axios Interceptor mit React Router V4 umleiten?

Ich möchte eine Umleitung in Axios-Interceptors durchführen, wenn ein Fehler 403 empfangen wird. Wie kann ich jedoch auf die Historie außerhalb von React-Komponenten zugreifen?

In Programmgesteuert in React-Router v4 ist es im Kontext einer React-Komponente, aber hier versuche ich es im Axios-Kontext

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);
});
10
hilderic sb

Ich habe das Problem gelöst, indem ich von außerhalb des Komponentenbaums auf meinen Redux Store zugegriffen habe und meine gleiche Aktion über die Schaltfläche "Abmelden" gesendet habe, da meine Interceptors in einer separaten Datei erstellt und vor dem Laden einer Komponente geladen werden. 

Also im Grunde habe ich Folgendes getan:

Bei index.js-Datei:

//....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'));

Und in der network-service.js-Datei: 

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);
    });

  }
};

Zu guter Letzt habe ich ein HOC (Higher Order Component), in das ich meine geschützten Komponenten einwickle, wo ich die eigentliche Weiterleitung durchführen kann, wenn die Sitzung beendet ist. Auf diese Weise wird beim Auslösen des Aktionstyps UNAUTH_USER meine isLogged-Eigenschaft in meinem session-Reduzierer auf false gesetzt. Daher wird diese Komponente jederzeit benachrichtigt und führt die Weiterleitung für mich durch.

Die Datei für die Komponente 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);
}

Hoffentlich hilft das!

18
DccBr

Ich habe diese Aufgabe gelöst, indem ich den Browserverlauf aus dem Paket history ( https://github.com/ReactTraining/history ) erstellt, an die Interceptor-Funktion übergeben und dann die .Push()-Methode daraus aufgerufen habe. 

Der Hauptdateicode (Teil davon):

// app.js
import createHistory from 'history/createBrowserHistory';
import httpService from './api_client/interceptors';

...

const history = createHistory();
httpService.setupInterceptors(store, history);

Interceptor-Konfiguration:

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);
    });
  },
};

Sie sollten auch Router aus react-router ( https://github.com/ReactTraining/react-router ) verwenden und dasselbe Verlaufsobjekt wie history param übergeben.

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

Hoffe das hilft!

11
Denys Kotsur

Die beste Lösung, die ich gefunden habe, ist die Definition von axios.interceptors in meinen Hauptreact-Komponenten und die Verwendung von that zur Fehlerbehandlung: (Und mit withRouter von Router V4)

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');
  }
2
hilderic sb

Das scheint für mich zu funktionieren 

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

Ich verwende React-Router-Dom und hat "historische" Requisiten, die beim Übergang zu einer neuen Route verwendet werden können

 history.Push('/newRoute')
0
pratik

Die akzeptierte Antwort löst mein Problem nicht. Nachdem ich Zeit mit Axios und Tickets um Interceptor verbracht habe, die nicht ausgelöst werden, habe ich festgestellt, dass Axios Interceptor nicht so dekorativ unterstützt, wie es oben beschrieben ist. für zukünftige Leser ist zu beachten, dass axios diesen global interceptor als Funktion markiert hat. also werden wir es vielleicht in der zukunft wirklich realisieren. für ref: https://github.com/axios/axios/issues/993

Ich habe eine einzige Axios-Instanz für alle API-Aufrufe, also habe ich die Definition des Interceptors darin gelöst. 

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

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

ReactTraining/Geschichte

0
fernandoxu