使用vuex的vue 2 JS中的Axios拦截器

时间:2017-12-22 19:51:24

标签: vue.js vuejs2 axios interceptor vuex

我在vuex商店成功登录之后存储令牌,如下所示:

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

axiosConfig是我只设置baseURL export default { baseURL: 'http://localhost/obiezaca/v2' }的文件,而params只是发送到后端的数据。

我的vuex文件看起来是:

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

它工作正常,我可以基于v-if="this.$store.state.logged"为已登录用户重新渲染我的SPA中的一些内容。我可以从整个应用中的任何组件访问this.$store.state.logged

现在我想将我的令牌添加到每个调用我的rest API后端的请求中。我已经创建了基本的axios http拦截器,如下所示:

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

现在我有2个问题/疑问。

  1. 我知道可以在每个组件中使用this.$store.state.loggedthis.$store.state.token,但是我可以在单个javascript文件中使用它吗?
  2. 我应该在哪里执行/启动拦截器javascript文件?这是独立的文件,它放在我的应用程序主文件夹中,但我没有在任何地方调用它,在之前我工作的angularJS中,我不得不在配置中添加$httpProvider.interceptors.push('authInterceptorService');但我不知道如何做同样的在vue架构中的东西。那么我应该在哪里注入我的拦截器?
  3. 修改

    我按照 GMaiolo 提示添加了

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

    到我的main.js文件中,我将我的拦截器重构为:

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

    此更改的结果是每个已经存在的后端调用(GET)不需要令牌才能停止工作,但这是合乎逻辑的,因为我没有澄清应该添加令牌的请求,以便它我试图在任何地方添加它,并且在我的拦截器中仍然存在错误,这就是每个已经存在的请求都停止工作的原因。

    当我尝试在浏览器控制台中进行后端POST调用时,我仍然会收到此错误:

      

    TypeError:无法读取属性' $ store'未定义的

    虽然我将商店导入我的拦截器文件。有任何想法吗?如果需要,我可以提供更多信息。

    我还添加了这个main,store和拦截器树结构的截图,这样你就可以看到我正在导入正确的路径:

    path

1 个答案:

答案 0 :(得分:22)

1

首先,我使用Vuex Module,因为此登录/会话行为似乎是Session模块的理想选择。在那之后(这是完全可选的)你可以设置Getter以避免从Vuex外部访问state本身,你最终会得到这样的结果:

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: {
  ...
}

设置好这些getter后,您可以从组件中轻松获取值。使用this.$store.getters.logged(或您想要使用的那个)或使用Vuex的mapGetters帮助程序[有关此内容的更多信息,您可以查看 getters docs] :

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

2

我喜欢在main.js创建,导入和执行interceptors.js助手时运行Axios的拦截器以及Vue即时消息。我会留下一个例子让你有个主意,但是,再一次,这是我自己的偏好:

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

在那里你最终会干净地封装所有行为。