【问题标题】:How to initialize the Vue app depending on back-end response first?如何首先根据后端响应初始化 Vue 应用程序?
【发布时间】:2022-01-01 08:10:42
【问题描述】:

我希望在应用程序中的任何其他内容之前运行一些代码,该代码将向后端发送请求,然后更新商店。 我需要先执行该部分,因为路由守卫依赖它,如何实现?

代码示例

获取用户信息和设置

async init() {
    await AuthService.initCSRF();
    await AuthService.getUser().then((res) => {
      if (res.data && res.data.user) {
        this.loginLocally(res.data.user);
      } else {
        this.logoutLocally();
      }
    });
}

身份验证保护

export function isLoggedIn(to, from, next) {
  console.log('Checked', store.state.auth.isLoggedIn);
  if (store.state.auth.isLoggedIn) {
    next();
    return;
  }

  next({ name: 'login' })
}

【问题讨论】:

  • 究竟什么依赖于init进程?您可以在调用 app mount() 之前等待它。问题是路由器可能不会等待应用程序安装并立即启动。如果是依赖于初始化的auth guard,则需要在router.beforeEach中等待init promise
  • 我只想执行一次,并且我还希望路由在执行时等待。

标签: api vue.js vuex settings guard


【解决方案1】:

在我的旧项目中,我做了类似的事情。希望你能有所了解。

app.js

import App from './components/App.vue'
store.dispatch('auth/attempt', sessionStorage.getItem('token')).then(() =>{
new Vue({
    el: '#app',
    router,
    store,
    render: h => h(App),
 });
});

这里我在渲染应用程序之前验证保存在本地存储中的令牌。

我的 Vuex 操作是这样的

async signIn({dispatch}, credentials) {
  let response = await axios.post("auth/signin", credentials);
  await dispatch('attempt', response.data.token)
},


async attempt({commit, state}, token) {
  if (token) {
    await commit('SET_TOKEN', token);

  }
  if (!state.token) {
    return;
  }

  try {
    let response = await axios.get('auth/me');
    commit('SET_USER', response.data)
  } catch (e) {
    commit('SET_TOKEN', null);
    commit('SET_USER', null);
  }
},
async signOut({commit}) {
  axios.post('auth/signout').then(() => {
    commit('SET_TOKEN', null);
    commit('SET_USER', null);
  });
}

我正在使用订阅者来监听突变并在请求标头中添加或删除令牌

import store from '../store'

store.subscribe((mutation) => {

 if (mutation.type === 'auth/SET_TOKEN') {
  if (mutation.payload) {
   axios.defaults.headers.common['Authorization'] = `Bearer ${mutation.payload}`;
  sessionStorage.setItem('token', mutation.payload);
} else {
  axios.defaults.headers.common['Authorization'] = null;
  sessionStorage.removeItem('token');
  }
 }
});

最后是一个用于处理令牌过期的 axios 拦截器。

import router from '../plugins/router'
import store from '../store'
import axios from "axios";

axios.interceptors.response.use((response) => {

  return response;
}, (error) => {
if (error.response.status) {
  if (error.response.status === 401) {

  if (router.currentRoute.name !== 'landing') {
    store.dispatch('auth/clearToken').then(() => {
      router.replace({
        name: 'landing'
      });

    }).finally(() => {
      swal.fire(
        'Your Session is Expired',
        'Please sign in again!',
        'error'
      )
    });
    }
  }
}

return Promise.reject(error);
});

【讨论】:

    【解决方案2】:

    在调用.mount(...) 之前可以等待初始化承诺。问题是Vue路由器启动separately from the application不会这样延迟。

    如果是router依赖初始化过程,延迟router启动的一种方法是等待router hook中的promise在其他之前触发:

    const initPromise = init();
    
    ...
    
    router.beforeEach(async (to, from, next) => {
      await initPromise;
      next();
    });
    

    【讨论】:

    • 但是这样initPromise 将在用户每次转到另一条路线时执行,对吗?我怎样才能只执行一次?
    • 承诺没有被执行。他们正在等待。如果在 beforeEach 之外调用 init() 一次,它会被调用一次
    猜你喜欢
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    相关资源
    最近更新 更多