Vue.js: Nuxt错误处理

48

在vuex中设置错误处理有些困难。似乎有很多方法可以做到这一点,但关于正确的错误处理方式却很少有文档。我尝试了四种替代方案,但还没有找到满意的解决方案。


替代方案1 - 在组件上捕获和处理错误

pages/login.vue文件中:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.push('/home');
            }).catch((error) {
                // handle error in component
            });
        },
    },
}

位于store/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        });
    },
}

优点

  • 嗯。

缺点

  • 未处理的错误没有存储在 vuex 中。
  • 在组件方法中引入了大量的样板代码。

替代方案2 - 在 vuex 中捕获和处理错误

pages/login.vue:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.push('/home');
            });
        },
    },
}

store/auth.js:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        }).catch((error) => {
            // store error in application state
            commit('SET_ERROR', error);
        });
    },
}

优点

  • 错误对象可以从任何组件中使用vuex访问。
  • 在布局中可以使用响应式错误组件,当错误状态改变时该组件会被显示出来。

缺点

  • 我不确定是否有办法跟踪错误的来源和抛出错误的组件。

替代方案3 - 使用axios拦截器捕获错误

plugins/axios.js:

export default function({ $axios, store }) {
    $axios.onError(error => {
        store.dispatch('setError', error);
    });
}

pages/login.vue中:

export default {
    methods: {
        onLogin() {
            this.$store.dispatch('auth/login', {
                email: this.email,
                password: this.password,
            }).then(() => {
                this.$router.push('/home');
            });
        },
    },
}

store/auth.js文件中:

export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
        });
    },
}

优点

  • 全局错误处理
  • 不需要在vuex或组件中捕获错误
  • 无需样板代码

缺点

  • 所有异常都未处理,这意味着非axios错误未被捕获。

替代方案4 - 自定义错误插件

我正在尝试实现一个自定义插件来捕获所有异常,但我没有成功使其工作。

plugins/catch.js:

export default (ctx, inject) => {
    const catchPlugin = function (func) {
        return async function (args) {
            try {
                await func(args)
            } catch (e) {
                return console.error(e)
            }
        }
    };
    ctx.$catch = catchPlugin;
    inject('catch', catchPlugin);
}

pages/login.vue:

export default {
    methods: {
        onLogin: this.$catch(async function () {
            await this.$store.dispatch('auth/login', { email: this.email, password: this.password });
            this.$router.push('/home');
        }),
    },
}

优点

  • 没有模板代码。
  • 插件可捕获所有错误。

缺点

  • 我无法使其工作。 :(

我的印象是,vue/nuxt 的错误处理文档不足。是否有人能让第四种选择起作用?这是否是理想的选择?还有其他选择吗?传统的方法是什么?

感谢您的时间!


我认为关于axios拦截器的第三种方法非常适合全局处理错误。https://dev59.com/wlsV5IYBdhLWcg3wsQrf - Helping hand
最好的方法是使用“中间件”API文档 - stchr
4个回答

6
选项 #4 不起作用的原因是因为你返回了一个从未执行的函数:
function catchPlugin(outerFunction) {
   return function async innerFunction(args) {
     try {
       const data = await outerFunction(args);
       return { data } 
     } catch (error) {
       return { error }
     }
   }
}

用法:

const execute = catchPlugin((args) => {
  // do something
})

execute('myArgument');

你需要执行内部函数,才能使你的示例正常工作:

onLogin: this.$catch(async function () {
    await this.$store.dispatch('auth/login', { email: this.email, password: this.password });
    this.$router.push('/home');
})(), // mind the () :-)

不过...我认为在组件中处理错误并不是一件坏事,因为这与你的视图组件密切相关。例如,想想登录组件,如今我们看到的是一个全局错误处理程序(toastr),如果用户名/密码不正确,它会显示一个弹出消息。从我的经验来看,这并不是最好的行为方式,虽然是一个好的起点,但更好的方法是在组件附近添加显示具体错误信息的错误消息。这意味着您总是必须在组件本身中添加错误处理(与UI相关)。

我们公司也在面临此问题,同事们正在为同一产品工作。有人正在添加错误处理,而另一个人则没有......我认为唯一的解决方案是教育开发人员始终添加适当的错误处理。使用async/await语法倒也不难:

methods: {
   async login (email, password) {
      try {
         await this.$store.dispatch('auth/login', { email, password })
         // do something after login
      } catch (error) {
         // handle error
      }
   }
}

关于您的con,还有一件事情:未处理的错误存储在vuex中。为什么这是一个缺点?您需要全局访问错误吗?我经常看到人们在vuex中放置如此多无用的状态,而这些状态只在组件本身中使用。在组件内部拥有本地组件状态并不是坏事。由于它涉及登录,因此该错误应仅在登录组件中知道。


1
所以基本上结论是最好在组件内部处理错误,即使它看起来有点臃肿,但它会在正确的位置。 - undefined

3

action 中使用 Promise

Vuex 示例:

NEW_AUTH({ commit }) {
    return new Promise((resolve, reject) => {
      this.$axios.$get('/token').then((res) => {
        ...
        resolve();
      }).catch((error) => {
        reject(error);
      })
    })
  }

在页面中:
this.$store.dispatch('NEW_AUTH')
   .then(() => ... )
   .catch((error) => ... )

这不对 - Nuxt 中的所有操作都是异步的,因此没有必要再次将其包装在 Promise 中。 - Mieszczańczyk S.
只需将对$get的调用返回,因为它已经返回了一个Promise。 - Léo Martin

1
为了解决“备选方案2”中的问题,你可以采取以下措施之一:
(a) 传递组件名称或甚至对组件的引用;
(b) 在调用的组件中将错误持久化到状态中。然后在你的组件中检查是否存在错误并显示它。为此,你可以使用一个mixin来避免需要编写样板代码。
在“store/auth.js”中:
export const actions = {
    login({ commit }, { email, password }) {
        return this.$axios.post('/api/login', {
            email,
            password,
        }).then((res) => {
            doSomething(res);
            commit('save_to_state', { response: res });
        }).catch((error) => {
            commit('save_to_state', { error });
        });
    },
}

1
在每个Vuex模块的状态中创建一个error键。然后将给定组件的错误分派到其相关的Vuex模块中。接着创建一个全局处理程序来监视不同Vuex模块中的错误,如果触发了其中一个错误,则显示该错误。
// store/auth.js

export const state = () => {
  return {
    success: null,
    error: null
  }
}

export const actions = {
  async login({ commit }, { email, password }) {
    try {
      const response = await axios.post('/api/login', {
        email,
        password
      })
      commit('SET_SUCCESS', response)
    } catch(err) {
      commit('SET_ERROR', error)
    }
  }
}

export const mutations = {
  SET_SUCCESS(state, payload) {
    state.success = payload
  },
  SET_ERROR(state, payload) {
    state.error = payload
  }
}

// auth.vue

export default {
  methods: {
    onLogin() {
      try {
        await this.$store.dispatch('auth/login', {
          email: this.email,
          password: this.password
        })
        if (this.$store.state.auth.success) this.$router.push('/home')
      } catch (err) {
        console.log(err)
      }
    }
  }
}

// app.vue

export default {
  created() {
    this.$store.subscribe((mutation, state) => {
      if (mutation.type.includes('ERROR')) {
        // display error in global error output
        console.log(mutation.payload)
      }
    })
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接