Backbone模型的save()方法导致了POST而不是PUT请求。

7

我是一个Backbone模型:

var User = Backbone.Model.extend({
  idAttribute: '_id',

  url: '/api/user',

  defaults:
    { username: ''
    }
});

I fetch it:

var user = new User();

user.fetch();

现在,在我的一个视图中,作为“click”事件,我有以下代码:
toggleSubscription: function () {
  user.set('subscriptions', true);
  user.save();
}

这会触发POST请求。但是,由于记录已经存在于服务器上,并且自从我获取它以来(模型实例具有一个id属性),我认为Backbone应该执行PUT而不是POST。为什么它会执行POST呢?


请将以下内容放入toggleSubscriptions中:console.log(user.toJSON());和console.log(user.isNew());并将结果粘贴到此处。 - Daniel Aranda
5个回答

7

尝试检查user.isNew()

看起来你创建了一个没有ID的新模型,这就是为什么在Backbone.sync期间它试图添加它的原因。

更新:

以上完全正确。它会POST,因为它是一个新的模型(这意味着,它没有ID)。在获取模型之前,您需要给它一个ID。在您的示例中:

var user = new User();
user.fetch();
user.save(); // in XHR console you see POST

var user = new User({ id: 123 });
user.fetch();
user.save(); // in XHR console you see PUT

1
@OliverJosephAsh 不,当您尝试获取新模型时,id并不是从服务器获取的。只有在获取集合时,您的模型才会加载带有ids。 - mvbl fst
1
如果您有用户ID,并执行user = new User({ id: 123 }),则获取将起作用 - 没有ID时,它始终是一个新模型。就像我说的,当您获取集合时,它会加载具有ID的模型。但是当您使用new User()时 - 它会创建一个新的用户模型,现在您只能保存它(通过POST) - 在这种情况下,它将在服务器端获得一个ID并返回ID POST成功,并将更新此新用户模型。之后,您可以执行user.save(),它将执行PUT。 - mvbl fst
1
当你进行获取操作时,你希望Backbone如何知道要加载哪个模型?请阅读http://backbonejs.org/#Sync - 你总是使用GET来进行获取,所以你总是需要一个ID:read → GET /collection[/id](对于模型也是一样)。想一想 - 在服务器端,当你从数据库中读取特定记录时,你需要主键。这里也是一样的。 - mvbl fst
我想我差不多明白你的意思了。现在我已经在实例化“User”时给它一个ID。那么,现在应该从“/api/user/:id”获取GET吗?因为它仍然试图从“/api/user”获取。 - user1082754
我也遇到了这个问题。但是当我运行时,方法的类型是PUT。我认为这是因为我正在使用jquery-iframe-transport。我该如何解决这个问题?这只发生在编辑场景中,但在创建时却没有问题。 - lukaserat
显示剩余5条评论

4
如果模型还没有id,它被认为是新的。--http://backbonejs.org/#Model-isNew 如果模型还没有id,它被认为是新的... 因此backbone将执行PUT请求而不是POST请求。
通过在保存块中添加"type:'POST'",可以简单地覆盖此行为:
var fooModel = new Backbone.Model({ id: 1});

fooModel.save(null, {
  type: 'POST'
});

我猜应该是“将执行POST请求而不是PUT”,因为我们使用POST方法添加新对象,使用PUT方法更新或修改它们。 - Vihanga Bandara

2
使用 urlRoot 属性来设置基础 URL 为 /api/user。那么,
  1. 当您保存一个没有设置 _id 属性的模型时,它会 POST 到 /api/user
  2. 当您保存一个设置了 _id 属性的模型时,它会 PUT 到 /api/user/{_id}。请注意,它会自动将 _id 的值添加到基础 URL 中。
它会查找 _id 属性的值,因为您已经将该值设置为 idAttribute

1
服务器响应必须是这样的:
{
  _id : 111
}

因为您将“_id”设置为主键。当模型被获取时,请验证“_id”的值,它必须有一个值: console.log(model.get('_id'));
我的想法是您在backbone模型中将“_id”设置为主键,但服务返回的是“id”。 更新:添加正常行为的示例代码:
var UserModel = Backbone.Model.extend({
  idAttribute: '_id',

  url: '/api/user',

  defaults:
    { username: ''
    }
});
user = new UserModel({_id : 20});
user.save();
user = new UserModel();
user.save();

输出: PUT /api/user 405 (方法不允许) POST /api/user 404 (未找到)

请检查模型的第一个实例是否有ID并尝试进行PUT,但其他实例是POST。我无法重现您的问题,因此我的想法是问题出在您的服务器响应上。


我选择使用“_id”。model.get('_id')返回ID,model.id也是如此。 - user1082754
我更新了我的答案,尝试了您的用例,使用了您的模型,但我无法重现您的问题。您能否在此粘贴您的原始服务器响应?我认为问题就出在那里。 - Daniel Aranda

0

值得检查一下,也许 emulateHTTP 为真。这将把所有的 PUT 请求转换成带有额外 _method 头部的 POST 请求(您可能还想检查一下这个头部是否存在以确认这个想法)。


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