web-dev-qa-db-fra.com

Axios interceptor in vue 2 JS utilisant vuex

Je stocke jeton après connexion avec succès appel dans magasin vuex comme ceci:

axios.post('/api/auth/doLogin.php', params, axiosConfig)
    .then(res => {
        console.log(res.data); // token
        this.$store.commit('login', res.data);
    })

axiosConfig est un fichier dans lequel je ne base que baseURL export default { baseURL: 'http://localhost/obiezaca/v2' } et params n’est que des données envoyées au backend.

Mon fichier vuex est:

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        logged: false,
        token: ''
    },
    mutations: {
        login: (state, response) => {
            state.logged = true;
            state.token = response;
            console.log('state updated');
            console.log('state.logged flag is: '+state.logged);
            console.log('state.token: '+state.token);
        },
        logout: (state) => {
            state.logged = false;
            state.token = '';
        }
    }
});

Cela fonctionne correctement, je peux re-rendre une partie du contenu de mon SPA en me basant sur v-if="this.$store.state.logged" Pour un utilisateur connecté. Je suis en mesure d'accéder à this.$store.state.logged À partir de n'importe quel composant de toute mon application.

Maintenant, je veux ajouter mon jeton à chaque demande qui appelle mon backend API. J'ai créé un intercepteur http axios de base, qui ressemble à ceci:

import axios from 'axios';

axios.interceptors.request.use(function(config) {
    const token = this.$store.state.token;
    if(token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
}, function(err) {
    return Promise.reject(err);
});

Maintenant, j'ai 2 problèmes/questions à ce sujet.

  1. Je sais qu'il est possible d'utiliser this.$store.state.logged Ou this.$store.state.token Dans tous les composants, mais puis-je l'utiliser de la même manière dans un seul fichier javascript?
  2. Où dois-je exécuter/démarrer mon fichier javascript interceptor? C'est un fichier indépendant qui se trouve dans le dossier principal de mon application, mais je ne l'appelle nulle part. Dans angularJS sur lequel je travaillais auparavant, je devais ajouter $httpProvider.interceptors.Push('authInterceptorService'); dans la configuration, mais je ne sais pas comment faire de même. chose dans vue architecture. Alors, où devrais-je injecter mon intercepteur?

[~ # ~] éditer [~ # ~]

J'ai suivi GMaiolo astuces que j'ai ajoutées

import interceptor from './helpers/httpInterceptor.js';
interceptor();

dans mon fichier main.js et je refacture mon intercepteur à ceci:

import axios from 'axios';
import store from '../store/store';

export default function execute() {
    axios.interceptors.request.use(function(config) {
        const token = this.$store.state.token;
        if(token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    }, function(err) {
        return Promise.reject(err);
    });
}

Le résultat de ces changements est que tous les appels backend existants (GET) qui n’ont pas besoin de jeton pour fonctionner, ont cessé de fonctionner, mais c’est logique, car je n’ai pas précisé à quelle demande l’ajout devrait être effectué. quelque chose ne va toujours pas dans mon intercepteur et c’est pourquoi chaque requête existante a cessé de fonctionner.

Lorsque j'essaie d'appeler le backend POST dans la console du navigateur, j'obtiens toujours l'erreur suivante:

TypeError: Impossible de lire la propriété '$ store' de non définie

Bien que j'importe le magasin dans mon fichier d'intercepteur. Des idées? Je peux fournir quelques informations supplémentaires si nécessaire.

J'ajoute en outre une capture d'écran de cette arborescence principale, de magasin et d'intercepteur afin que vous puissiez voir que je suis en train d'importer depuis le chemin correct:

path

18
dopeCode

1.

Tout d'abord, j'utiliserais un Vuex Module car ce comportement de connexion/session semble être idéal pour un module Session. Après cela (ce qui est totalement optionnel), vous pouvez configurer un Getter pour éviter d’accéder au state lui-même depuis l’extérieur de Vuex, vous obtiendrez quelque chose comme ceci:

state: {
  // bear in mind i'm not using a module here for the sake of simplicity
  session: {
    logged: false,
    token: ''
  } 
},
getters: {
  // could use only this getter and use it for both token and logged
  session: state => state.session,
  // or could have both getters separated
  logged: state => state.session.logged,
  token: state => state.session.token
},
mutations: {
  ...
}

Avec ces getters set, vous pouvez obtenir les valeurs un peu plus facilement à partir de composants. Avec soit en utilisant this.$store.getters.logged (ou celui que vous voudriez utiliser) ou en utilisant l’assistant mapGetters de Vuex [pour plus d’informations à ce sujet, vous pouvez vérifier le getters docs]:

import { mapGetters } from 'vuex'
export default {
  // ...
  computed: {
    ...mapGetters([
      'logged',
      'token'
    ])
  }
}

2.

J'aime utiliser les intercepteurs d'Axios avec Vue instantation in main.js créer, importer et exécuter un interceptors.js assistant. Je laisserais un exemple pour que vous ayez une idée, mais là encore, c'est ma propre préférence:

main.js

import Vue from 'vue';
import store from 'Src/store';
import router from 'Src/router';
import App from 'Src/App';

// importing the helper
import interceptorsSetup from 'Src/helpers/interceptors'

// and running it somewhere here
interceptorsSetup()

/* eslint-disable no-new */
new Vue({
    el: '#app',
    router,
    store,
    template: '<App/>',
    components: { App }
});

interceptors.js

import axios from 'axios';
import store from 'your/store/path/store'

export default function setup() {
    axios.interceptors.request.use(function(config) {
        const token = store.getters.token;
        if(token) {
            config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
    }, function(err) {
        return Promise.reject(err);
    });
}

Et là, vous finissiez par avoir tout le comportement clairement encapsulé.

25
GMaiolo