【问题标题】:Axios interceptor in vue 2 JS using vuex使用 vuex 的 vue 2 JS 中的 Axios 拦截器
【发布时间】:2018-06-05 09:54:36
【问题描述】:

我在成功登录调用后将令牌存储在 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 架构中做同样的事情.那么我应该在哪里注入我的拦截器呢?

编辑

我遵循了我添加的 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”

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

我另外添加了这个主、存储和拦截器树结构的屏幕截图,这样你就可以看到我正在从正确的路径导入:

【问题讨论】:

    标签: vue.js vuejs2 axios interceptor vuex


    【解决方案1】:

    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 文档]:

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

    2.

    我喜欢在 main.js 创建、导入和执行 interceptors.js 帮助程序时与 Vue 实例一起运行 Axios 的拦截器。我会留下一个例子,让你有一个想法,但是,再说一遍,这是我自己的偏好:

    ma​​in.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);
        });
    }
    

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

    【讨论】:

    • 我声明令牌成本的行导致此错误:TypeError: Cannot read property '$store' of undefined at eval (httpInterceptor.js?c694:5)。我没有使用 Getter 来收集它,但我尝试使用 this.$store.state.token; 来完成它。我也应该在那里导入 vuex 吗?或者也许我必须在这种情况下使用这个吸气剂?
    • 我的拦截器中似乎没有this.$store.state.token
    • 是的!您必须从 interceptors.js 中导入商店,我的错!
    • 我添加了编辑,请看一下。我还在和这个拦截器战斗。
    • @BT101 检查我更新的答案,您必须直接从拦截器脚本文件导入商店
    【解决方案2】:

    我做了同样的逻辑。但是,我只是更改文件名。我使用了 axios/index.js 但商店在那里没有定义。所以我只是更改了文件名 axios/interceptor.js 并且不知道存储数据是否可以访问look at my below image

    【讨论】:

      猜你喜欢
      • 2018-11-01
      • 2019-03-27
      • 2020-09-20
      • 2018-04-25
      • 2020-09-16
      • 2020-06-04
      • 2019-02-11
      • 2021-10-03
      • 2019-06-26
      相关资源
      最近更新 更多