有没有更好的方法来处理 laravel 和 vue js 的 axios 错误

Posted

技术标签:

【中文标题】有没有更好的方法来处理 laravel 和 vue js 的 axios 错误【英文标题】:is there any better way to handling axios error with laravel and vue js 【发布时间】:2018-08-22 01:46:48 【问题描述】:

所以我正在使用 laravel 作为我的后端和 vue js 作为 spa 前端框架来创建 spa 网络应用程序。我正在使用 laravel 护照通过 api 进行身份验证。我正在使用 vuex 来控制我的应用程序状态。

首先我创建一个 api 文件来与 axios 的 api 交互

import  BKCU_CONFIG  from '../config.js';

export default 

  getArtikelS: function( p )
    return axios.get( BKCU_CONFIG.API_URL + '/artikel' + `?column=$p.column&direction=$p.direction&per_page=$p.per_page&page=$p.page&search_column=$p.search_column&search_operator=$p.search_operator&search_query_1=$p.search_query_1&search_query_2=$p.search_query_2`);
  ,

  getArtikelCUS: function( p, id )
    return axios.get( BKCU_CONFIG.API_URL + '/artikel/indexCU/' + id + `?column=$p.column&direction=$p.direction&per_page=$p.per_page&page=$p.page&search_column=$p.search_column&search_operator=$p.search_operator&search_query_1=$p.search_query_1&search_query_2=$p.search_query_2`);
  ,

  getArtikel: function( id )
    return axios.get(BKCU_CONFIG.API_URL + '/artikel/' + id);
  ,

  createArtikel: function()
    return axios.get(BKCU_CONFIG.API_URL + '/artikel/create');
  ,

  storeArtikel: function ( form )
    return axios.post(BKCU_CONFIG.API_URL + '/artikel/store', form);
  ,

  editArtikel: function( id )
    return axios.get(BKCU_CONFIG.API_URL + '/artikel/edit/' + id);
  ,

  updateArtikel: function ( id, form )
    return axios.post(BKCU_CONFIG.API_URL + '/artikel/update/' + id, form);
  ,

  updateTerbitkan: function( id )
    return axios.post(BKCU_CONFIG.API_URL + '/artikel/updateTerbitkan/' + id);
  ,

  updateUtamakan: function( id )
    return axios.post(BKCU_CONFIG.API_URL + '/artikel/updateUtamakan/' + id);
  ,

  deleteArtikel: function( id )
    return axios.delete(BKCU_CONFIG.API_URL + '/artikel/' + id);
  

然后我为每个模型创建一个 vuex 模块。像这样的文章:

import ArtikelAPI from '../../api/artikel.js';

export const artikel = 
  state: 
    artikelS: [],
    artikelLoadStatS: '',
    artikel: ,
    artikelLoadStat: '',
    artikelUpdate: '',
    artikelUpdateStat: '',
    artikelRules: [],
    artikelOption: [],
  ,

  actions: 

    // load all
    loadArtikelS(  commit , p )
      commit('setArtikelLoadStatS', 'loading');

      ArtikelAPI.getArtikelS( p )
        .then( function( response )
          commit('setArtikelS', response.data.model);
          commit('setArtikelLoadStatS', 'success');
        )
        .catch( error => 
          commit('setArtikelS', error.response);
          commit('setArtikelLoadStatS', 'fail');
        );
    ,

    // load by cu
    loadArtikelCUS(  commit , [p, id] )
      commit('setArtikelLoadStatS', 'loading');

      ArtikelAPI.getArtikelCUS( p, id )
        .then( function( response )
          commit('setArtikelS', response.data.model);
          commit('setArtikelLoadStatS', 'success');
        )
        .catch( error => 
          commit('setArtikelS', error.response);
          commit('setArtikelLoadStatS', 'fail');
        );
    ,

    // load single data
    loadArtikel( commit, id )
      commit('setArtikelLoadStat', 'loading');

      ArtikelAPI.getArtikel( id )
        .then( function( response )
          commit('setArtikel', response.data );
          commit('setArtikelLoadStat', 'success');
        )
        .catch( error => 
          commit('setArtikelS', error.response);
          commit('setArtikelLoadStatS', 'fail');
        );
    ,

    // create page
    createArtikel( commit )
      commit('setArtikelLoadStat', 'loading');

      ArtikelAPI.createArtikel()
        .then( function( response )
          commit('setArtikel', response.data.form );
          commit('setArtikelRules', response.data.rules);
          commit('setArtikelOption', response.data.option)
          commit('setArtikelLoadStat', 'success');
        )
        .catch( function()
          commit('setArtikel', []);
          commit('setArtikelRules', []);
          commit('setArtikelOption', [])
          commit('setArtikelLoadStat', 'fail');
        );
    ,

    // store data
    storeArtikel( commit, state, dispatch, form )
      commit('setArtikelUpdateStat', 'loading');

      ArtikelAPI.storeArtikel( form )
        .then( function( response )
          if(response.data.saved)
            commit('setArtikelUpdate', response.data);
            commit('setArtikelUpdateStat', 'success');
          else
            commit('setArtikelUpdateStat', 'fail');
          
        )
        .catch(error => 
          if (error.response.status) 
            this.errors = error.response.data;
            commit('setArtikelUpdate', this.errors);         
          else
            commit('setArtikelUpdate', 'Oops terjadi kesalahan :(');
          
          commit('setArtikelUpdateStat', 'fail');
        );
    ,

    // edit page
    editArtikel( commit, id )
      commit('setArtikelLoadStat', 'loading');

      ArtikelAPI.editArtikel( id )
        .then( function( response )
          commit('setArtikel', response.data.form );
          commit('setArtikelRules', response.data.rules);
          commit('setArtikelOption', response.data.option)
          commit('setArtikelLoadStat', 'success');
        )
        .catch( function()
          commit('setArtikel', []);
          commit('setArtikelRules', []);
          commit('setArtikelOption', [])
          commit('setArtikelLoadStat', 'fail');
        );
    ,

    // update data
    updateArtikel( commit, state, dispatch, [id, form] )
      commit('setArtikelUpdateStat', 'loading');

      ArtikelAPI.updateArtikel( id, form )
        .then( function( response )
          if(response.data.saved)
            commit('setArtikelUpdate', response.data);
            commit('setArtikelUpdateStat', 'success');
          else
            commit('setArtikelUpdateStat', 'fail');
          
        )
        .catch(error => 
          if (error.response.status) 
            this.errors = error.response.data;
            commit('setArtikelUpdate', this.errors);         
          else
            commit('setArtikelUpdate', 'Oops terjadi kesalahan :(');
          
          commit('setArtikelUpdateStat', 'fail');
        );
    ,
    updateArtikelTerbitkan( commit, state, dispatch, id )
      commit('setArtikelUpdateStat', 'loading');

      ArtikelAPI.updateTerbitkan( id )
        .then( function( response )
          if(response.data.saved)
            commit('setArtikelUpdate', response.data);
            commit('setArtikelUpdateStat', 'success');
          else
            commit('setArtikelUpdateStat', 'fail');
          
        )
        .catch(error => 
          if (error.response.status) 
            this.errors = error.response.data;
            commit('setArtikelUpdate', this.errors);         
          else
            commit('setArtikelUpdate', 'Oops terjadi kesalahan :(');
          
          commit('setArtikelUpdateStat', 'fail');
        );
    ,
    updateArtikelUtamakan( commit, state, dispatch, id )
      commit('setArtikelUpdateStat', 'loading');

      ArtikelAPI.updateUtamakan( id )
        .then( function( response )
          if(response.data.saved)
            commit('setArtikelUpdate', response.data);
            commit('setArtikelUpdateStat', 'success');
          else
            commit('setArtikelUpdateStat', 'fail');
          
        )
        .catch(error => 
          if (error.response.status) 
            this.errors = error.response.data;
            commit('setArtikelUpdate', this.errors);         
          else
            commit('setArtikelUpdate', 'Oops terjadi kesalahan :(');
          
          commit('setArtikelUpdateStat', 'fail');
        );
    ,

    // delete data
    deleteArtikel( commit, state, dispatch, id )
      commit('setArtikelUpdateStat', 'loading');

      ArtikelAPI.deleteArtikel( id )
        .then( function( response )
          if(response.data.saved)
            commit('setArtikelUpdate', response.data);
            commit('setArtikelUpdateStat', 'success');
          else
            commit('setArtikelUpdateStat', 'fail');
          
        )
        .catch(error => 
          if (error.response.status) 
            this.errors = error.response.data;
            commit('setArtikelUpdate', this.errors);         
          else
            commit('setArtikelUpdate', 'Oops terjadi kesalahan :(');
          
          commit('setArtikelUpdateStat', 'fail');
        );
    ,

    // reset status
    resetArtikelUpdateStat( commit )
      commit('setArtikelUpdateStat', '');
    
  ,

  mutations: 
    setArtikelS ( state, artikelS )
      state.artikelS = artikelS;
    ,
    setArtikelLoadStatS( state, status )
      state.artikelLoadStatS = status;
    ,
    setArtikel ( state, artikel )
      state.artikel = artikel;
    ,
    setArtikelLoadStat( state, status )
      state.artikelLoadStat = status;
    ,
    setArtikelUpdateStat( state, status )
      state.artikelUpdateStat = status;
    ,
    setArtikelUpdate( state, data )
      state.artikelUpdate = data;
    ,
    setArtikelRules( state, rules )
      state.artikelRules = rules;
    ,
    setArtikelOption( state, option )
      state.artikelOption = option;
    
  ,

  getters: 
    getArtikelS( state )
      return state.artikelS;
    ,
    getArtikelLoadStatS ( state )
      return state.artikelLoadStatS;
    ,
    getArtikel( state )
      return state.artikel;
    ,
    getArtikelLoadStat ( state )
      return state.artikelLoadStat;
    ,
    getArtikelUpdateStat ( state )
      return state.artikelUpdateStat;
    ,
    getArtikelUpdate ( state )
      return state.artikelUpdate;
    ,
    getArtikelRules ( state )
      return state.artikelRules;
    ,
    getArtikelOption ( state )
      return state.artikelOption;
    
  

如您所见,我的每个操作都包含一个错误捕获,它只捕获错误并显示消息。我发现这种处理方式有一些缺点

也许有人可以帮助我改进这种工作流程,一切正常且非常结构化,但我发现缺少错误捕获,例如:

    因为我使用的是 laravel,所以我的令牌有时间过期(因为用户离开他们的电脑一段时间或其他事情)所以它会以不太用户友好的方式显示经过身份验证的错误消息,我想要它只需将用户重定向到登录页面以重新登录,然后返回到当前用户所在的页面 我想我在这里做了很多重复的代码,我可以为所有这些 axios 请求做一个单一的错误处理吗?

【问题讨论】:

您可以编写一个通用的拦截器,但您现在的做法的优点是每个都以特定的方式处理错误。如果你写了一个通用的拦截器,你会失去它。 【参考方案1】:

你可以使用拦截器。但是,后端应该关心错误并将相应的消息发送给前端。

request.interceptors.response.use(response => 
  return response
, error =>  
  //Put your logic here to manage the error message coming from BE

  return Promise.reject(error )
)

如需完整示例,请查看我如何在我的应用中实现整个 axios 实例:

(我已经使用 vuetify 快餐栏组件显示错误信息)

import axios from 'axios'
import  store  from "../../store/store"
import  eventBus  from "../main";

const request = axios.create(
  baseURL: 'http://localhost:8000'
)

request.interceptors.request.use(request => 
  const token = store.state.token
  if (token) 
    request.headers.Authorization = 'Bearer ' + token
  
  return request

, error => 
  return Promise.reject(error)
)

request.interceptors.response.use(response => 
  return response
, error =>  //getting error from backend and display it with snackbar(vuetify component)
   eventBus.$emit('snackBar', 
     text: error.response.data.message,
     snackbarColor: 'red darken-4'
   )

  return Promise.reject(error )
)

export default request

使用 Laravel 的示例错误消息:

return response()->json(["message" => "You have not access to perform this action"],403);

【讨论】:

【参考方案2】:

你可以使用 axios 的一些特性来摆脱这个样板

使用拦截器

 axios.interceptors.response.use(response => 
  return response.data;
 , error => 
 if (error.response && error.response.data) 
  // handle your errors here.
  handleServerErrors(error.response.data);
 
 return Promise.reject(error);
);

使用 axios 默认值

axios.defaults.timeout = 5000;
axios.defaults.baseURL = BKCU_CONFIG.API_URL

不要再连接网址了。由于您已经设置了默认网址,您可以这样做

getArtikel: function( id )
   return axios.get('/artikel/' + id);

使用 ES6 特性和 axios 参数,这样你就可以打开它

getArtikelS: function( p )
 return axios.get( BKCU_CONFIG.API_URL + '/artikel' + `?column=$p.column&direction=$p.direction&per_page=$p.per_page&page=$p.page&search_column=$p.search_column&search_operator=$p.search_operator&search_query_1=$p.search_query_1&search_query_2=$p.search_query_2`);
,

变成这样更好的东西

   getArtikelS(p)
     return axios.get(`/artikel`, params: p)
   

Axios 支持将参数作为对象,因此您不必编写奇怪的查询字符串:)

最后一个提示:不要将所有内容都存储到 vuex 中。如果您不需要超过 1 个组件中的数据,请直接在您的组件中调用 api。

【讨论】:

以上是关于有没有更好的方法来处理 laravel 和 vue js 的 axios 错误的主要内容,如果未能解决你的问题,请参考以下文章

Vue:处理多个 API 调用的最佳实践

寻找一种更好的方法来使用 Laravel 处理大型 XML 文件以将部分导入 MySQL 数据库

有没有更好的方法来使用存储库在 Laravel 中分配 Eloquent 关系?

如何在 SPA 中处理角色/权限(Laravel+Vue)

Vue SPA 的 Laravel 电子邮件验证

有没有更好的方法在 PHP / Laravel 中编写这句话? [复制]