使用 Ember.js 数据 RESTAdapter 时应该如何处理错误?

Posted

技术标签:

【中文标题】使用 Ember.js 数据 RESTAdapter 时应该如何处理错误?【英文标题】:How should errors be handled when using the Ember.js Data RESTAdapter? 【发布时间】:2012-10-09 17:57:16 【问题描述】:

ember-data.js:https://github.com/emberjs/data/tree/0396411e39df96c8506de3182c81414c1d0eb981

简而言之,当出现错误时,我想在视图中显示错误信息,然后用户可以 1)取消,这将回滚事务 2)更正输入错误并成功提交事务,通过服务器上的验证。

下面是来自源代码的代码 sn-p。它不包含错误回调。

updateRecord: function(store, type, record) 
  var id = get(record, 'id');
  var root = this.rootForType(type);

  var data = ;
  data[root] = this.toJSON(record);

  this.ajax(this.buildURL(root, id), "PUT", 
    data: data,
    context: this,
    success: function(json) 
      this.didUpdateRecord(store, type, record, json);
    
  );
,

总的来说,从服务器接收错误并更新视图的流程是什么?似乎错误回调应该将模型置于isError 状态,然后视图可以显示适当的消息。此外,交易应该保持肮脏。这样,交易就可以使用rollback

不过,使用store.recordWasInvalid 似乎是朝着正确的方向发展。

【问题讨论】:

目前还没有完善的错误处理机制,请看github.com/emberjs/data/pull/376,或许你会找到你想要的。 是的,缺少错误处理令人惊讶,但是没有错误处理,而不是稍后会更改的幼稚实现,这很好。我已经编写了我最近的 Ember 应用程序,通过在客户端执行一些验证来避免服务器错误,然后再执行 App.store.commit() 【参考方案1】:

这个周末我试图弄清楚同样的事情。根据 Luke 所说的,我仔细查看了 latest commit(12 月 11 日)的 ember 数据源。

TLDR;要处理 ember-data 更新/创建错误,只需在您的 DS.Model 实例上定义 becameError()becameInvalid(errors)。 RESTadapter的AJAX错误回调触发的级联最终会调用你定义的这些函数。

例子:

App.Post = DS.Model.extend
  title: DS.attr "string"
  body: DS.attr "string"

  becameError: ->
    # handle error case here
    alert 'there was an error!'

  becameInvalid: (errors) ->
    # record was invalid
    alert "Record was invalid because: #errors"

这里是完整的源代码:

在REST适配器中,AJAX回调错误函数被赋予here:

   this.ajax(this.buildURL(root, id), "PUT", 
      data: data,
      context: this,
      success: function(json) 
        Ember.run(this, function()
          this.didUpdateRecord(store, type, record, json);
        );
      ,
      error: function(xhr) 
        this.didError(store, type, record, xhr);
      
    );

didError 被定义为here 并根据响应依次调用商店的recordWasInvalid 或recordWasError:

  didError: function(store, type, record, xhr) 
    if (xhr.status === 422) 
      var data = JSON.parse(xhr.responseText);
      store.recordWasInvalid(record, data['errors']);
     else 
      store.recordWasError(record);
    
  ,

反过来,store.recordWasInvalidstore.recordWasError(定义为 here)调用记录(DS.Model)的处理程序。在无效的情况下,它会将来自适配器的错误消息作为参数传递。

 recordWasInvalid: function(record, errors) 
    record.adapterDidInvalidate(errors);
  ,

  recordWasError: function(record) 
    record.adapterDidError();
  ,

DS.Model.adapterDidInvalidateadapterDidError(定义为 here)只是 send('becameInvalid', errors)send('becameError') 最终将我们引向处理程序 here:

  didLoad: Ember.K,
  didUpdate: Ember.K,
  didCreate: Ember.K,
  didDelete: Ember.K,
  becameInvalid: Ember.K,
  becameError: Ember.K,

(Ember.K 只是一个用于返回this 的虚拟函数。参见here)

因此,结论是,您只需在模型上为 becameInvalidbecameError 定义函数即可处理这些情况。

希望这对其他人有所帮助;文档现在肯定没有反映这一点。

【讨论】:

如果您想根据上下文以不同方式处理错误,您还可以通过在提交事务之前添加model.one('becameInvalid', function() // error handling here ) 来使用一次性回调。 很好的解释!非常感谢。 这里有很好的解释。唯一没有涉及的是如何将错误传播到模型,以便 Ember.Route 的错误事件可以相应地采取行动。用户可能导航到了一个不存在的 ID,在这种情况下,您希望为他们提供正确的错误。所以把这个和上面的答案结合起来可能是有意义的。 STALE:对 422 状态的检查似乎已移至 active_model_adapter:github.com/emberjs/data/blob/… 从服务器检索到的 json 哈希必须有 "errors" 键,其中包含错误。否则会引发错误。【参考方案2】:

DS.RESTAdapter 刚刚在 this commit 中获得了更多的错误处理,但我们还没有达到对错误处理提出很好建议的地步。

如果您现在有足够的野心/疯狂地使用 ember-data 将应用程序投入生产(就像我一样!),最好确保您的 API 发生故障的可能性极低。即在客户端验证您的数据。

希望我们能在接下来的几个月里用更好的答案更新这个问题。

【讨论】:

Ember.Data 今天的错误处理状态如何?【参考方案3】:

我刚遇到这种情况,不确定是否已经在任何地方解释过。

我正在使用:

Em.VERSION : 1.0.0
DS.VERSION : "1.0.0-beta.6"
Ember Validations (dockyard) : Version: 1.0.0.beta.1
Ember I18n

该模型最初是与 Validation mixin 混合的。

App.Order = DS.Model.extend(Ember.Validations.Mixin, 
.....
someAttribute : DS.attr('string'),
/* Client side input validation with ember-validations */
validations : 
    someAttribute : 
        presence : 
            message : Ember.I18n.t('translations.someAttributeInputError')
        
    

);

在模板中,添加了相应的车把。 (请注意,在输入验证的情况下,ember 验证会自动将错误添加到 model.errors.<attribute>,我也会在服务器验证中使用相同的权衡)

<p>t 'translations.myString'<br>
  view Ember.TextField valueBinding="attributeName"
  #if model.errors.attributeName.length<small class="error">model.errors.attributeName</small>/if
</p

现在,我们将保存Order

App.get('order').save().then(function () 
  //move to next state?
, function(xhr)
  var errors = xhr.responseJSON.errors;
  for(var error in errors) //this loop is for I18n
    errors[error] = Ember.I18n.t(errors[error]);
  
  controller.get('model').set('errors', errors); //this will overwrite current errors if any
);

现在如果服务器抛出一些验证错误,返回的数据包是

"errors":"attributeName1":"translations.attributeNameEror",
 "another":"translations.anotherError"

status : 422

使用状态422

很重要

这样,您的属性可以在客户端和服务器端再次验证。

免责声明:我不确定这是否是最好的方法!

【讨论】:

【参考方案4】:

由于目前在 Ember-Data 中没有好的解决方案,我通过向 DS.Model 添加 apiErrors 属性,然后在我的 RestAdapter 子类(我已经需要我自己的)中添加了错误回调来创建自己的解决方案Ajax 调用 createRecordupdateRecord 保存错误并将模型置于“无效”状态,这应该意味着客户端或服务器端验证失败。

这里是sn-ps的代码:

这可以放在 application.js 或其他一些***文件中:

DS.Model.reopen(
  // Added for better error handling on create/update
  apiErrors: null
);

这会出现在 RestAdapter 子类中 createRecordupdateRecord 的错误回调中:

error: function(xhr, textStatus, err) 
    console.log(xhr.responseText);
    errors = null;
    try 
        errors = JSON.parse(xhr.responseText).errors;
     catch(e) //ignore parse error
    if(errors) 
        record.set('apiErrors',errors);
    
    record.send('becameInvalid');

【讨论】:

以上是关于使用 Ember.js 数据 RESTAdapter 时应该如何处理错误?的主要内容,如果未能解决你的问题,请参考以下文章

ember.js 和服务器

ember.js 如何插入新记录?

css Ember.js模型生成器 - 将JSON对象反向工程为Ember数据模型

基于布尔值过滤模板中的 Ember.js 数据

如何在ember js中从子组件调用父组件方法

图片上传Ember JS和Sails JS