【问题标题】:How to force a POST request when saving a model?保存模型时如何强制 POST 请求?
【发布时间】:2016-12-11 19:46:39
【问题描述】:

我需要对服务器端 API 进行 POST。我必须将id 密钥发送到服务器的请求正文中。

我使用 Backbone 模型。但是当我这样做时:

myModel.set("id", somevalue)    
myModel.save()

被触发的网络请求是:URL/someValue [PUT]

Backbones 不执行 POST 而是执行 PUT,并将 id 附加到 url。

所以我只想在没有 Backbone 通知的情况下将 id 密钥传递给服务器。

【问题讨论】:

标签: javascript rest backbone.js backbone-model


【解决方案1】:

来自Backbone's doc

Backbone 已预先配置为与 RESTful API 同步。

[...]

默认的 sync handler 将 CRUD 映射到 REST,如下所示:

  • 创建POST /collection
  • 阅读GET /collection[/id]
  • 更新PUT /collection/id
  • 补丁PATCH /collection/id
  • 删除DELETE /collection/id

新条目没有 ID,因此如果您在保存模型之前为其提供 ID,Backbone 会默认为 PUT 请求,因为它认为您要保存现有条目。

如何使用 id 发起 POST 请求?

选择以下解决方案之一。

坚持使用 RESTful API

这是显而易见的。如果可以,请坚持标准。

更改 API 以处理 PUT/PATCH 请求,并且仅在创建时使用 POST。让 API 端点从 URL 中获取 ID。

RESTful API best practices

传递type 选项1

简单且非常适合一次性使用。

传递给save(或fetch)的每个选项都会覆盖sync函数默认定义的选项并传递给jQuery.ajax function

Backbone sync source

// Make the request, allowing the user to override any Ajax options.
var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
var url = model.url(); // get the url before setting the `id`
model.save({ 
    id: somevalue 
}, { 
    url: url, // fix the url
    type: 'POST' // choose the HTTP verb
});

修复模型使用的url很简单,你也有一些选择:

重写 url 函数 (source) 适用于每次调用都应使用特定 url 而不附加默认 id 的情况。

var MyModel = Backbone.Model.extend({
    url: function() {
        return _.result(this, 'urlRoot') ||
            _.result(this.collection, 'url') ||
            urlError();
    }
});

在模型上设置idAttribute

这取决于您尝试传递的 id 在数据中的含义。

Backbone 模型使用"id" 具有默认的id 属性名称。您可以通过覆盖模型的idAttribute property 来指定不同的名称。无论名称如何,它始终通过model.id property 自动提供。

现在,假设 id 属性与此模型无关,并且此模型的真实 id 属性名称类似于 UID,您可以更改模型的 idAttribute 以反映属性的真实名称(或者它甚至可以是一个永远不会成为属性的字符串)。

var MyModel = Backbone.Model.extend({
    idAttribute: 'UID',
});

现在,id 属性不被视为当前模型的 id,model.isNew() 将返回 true,发送 POST 请求以在保存时创建它。

改变sync/save函数行为

如果您使用的 API 不是 RESTful,您可以通过覆盖sync function 来调整行为。这可以在模型或集合上完成,也可以在集合和模型默认使用的Backbone.sync function 上完成。

例如,如果您想让每个请求默认使用 POST 来处理 MyModel 类:

var MyModel = Backbone.Model.extend({
    sync: function(method, model, options) {
        return Backbone.sync.call(this, method, model,
            _.extend({ type: 'POST' }, options));
    }
});

您可以只使用 save 函数执行类似的操作,让 fetch 像往常一样执行其 GET 请求。

使用emulateHTTP setting2

如果您想使用不支持的旧版 Web 服务器 Backbone 默认的 REST/HTTP 方式,你可以选择开启 Backbone.emulateHTTP。设置此选项将伪造PUTPATCHDELETE 使用 HTTP 请求 POST,设置 X-HTTP-Method-Override 标头与 true 方法。

[...]

Backbone.emulateHTTP = true;

model.save();  // POST to "/collection/id", with "_method=PUT" + header.

不要覆盖isNew

这个模型已经保存到服务器了吗?如果模型还没有 有一个id,就被认为是新的。

本网站上的其他一些答案建议覆盖isNew function不要。该函数有其目的,并且重写它以强制 POST 请求是一个糟糕的 hack,而不是解决方案。

isNew 在内部使用,但也可以由您的代码或其他库和 Backbone 插件使用。


1虽然我没有从堆栈溢出中获取它,但它已经是an answer by Andrés Torres Marroquín on a similar question

2取自Maanas Royy's answer

【讨论】:

  • 感谢您的回答。对于第一个选项,我无法更改 API ...我测试了您的第二个选项(类型选项),它确实使用正文中的 id 键发出了一个发布请求。所以这很好,但它仍然在 url 的末尾附加了 id,所以不幸的是服务器不会接受它!对于第三个选项,我很难理解您的解决方案。 idAttribute 是主干的组件/功能还是您选择的随机名称?
  • 对于同步选项,如果我能够覆盖它,它不会覆盖我所有的实例吗?因为我不想破坏我的其他请求!谢谢。
  • @Doctor 我添加了一种方法来更改该特定请求的url
  • 我试图传递的 id 不能识别任何与我的模型相关联的有用信息。如果 API 开发人员将其称为其他名称(everithing 但不是 id),它就不会干扰骨干内部机制......
  • @Doctor 如果 id 属性没有识别出对该模型有用的任何内容,请使用 idAttribute 来达到此目的。您可以使用另一个名称,也许在此模型中从未使用过的名称,以避免与 Backbone 的默认行为发生冲突。
猜你喜欢
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多