星期日, 2012 年 2 月 26 日

Edge Rails:PATCH 成为新的首选 HTTP 方法用于更新

发布者 fxn

什么是 PATCH?

HTTP 方法 PUT 表示给定 URL 下的资源创建替换

例如,考虑文件。如果您在某个 URL 上将文件上传到 S3,那么您需要在该 URL 下创建文件或者替换现有文件(如果存在)。这是 PUT。

现在,假设一个 web 应用程序具有 Invoice 模型,带有 paid 标记,以指示发票是否已支付。您如何用 RESTful 方式设置该标记?经由 PUT 将 paid=1 提交到 /invoices/:id 不符合 HTTP 语义,因为此类请求不会发送发票的完整表示形式以用于替换

在 GET、POST、PUT、DELETE 方法的约束下,传统答案是将给定发票的 paid 标记本身定义为一个资源。因此,您可以定义一个路由,以便能够将 paid=1 PUT 到 /invoices/:id/paid。您必须这样做,因为 PUT 不允许对资源进行部分更新

现在,让我们思考一般 Ruby on Rails 应用程序中的普通编辑表单。我们有多少次发送完整表示形式以进行替换?不总是这样做,也许我们可以说,实际上您这样做甚至很少。例如,一般来说,最终用户不能设置 created_atupdated_at 时间戳,尽管通常认为它们属于映射到记录的资源的表示形式。

PUT 还是一种幂等方法。您应该能够多次播放请求并获取相同的资源,在使用嵌套属性创建子资源同时更新父资源的传统习语中,有时会违反这一点。

没有理论阻止 PUT 进行部分更新,但是当 HTTP 被标准化时,替换语义已经被应用。

因此,在 1995 年,定义了 PATCH 方法,并对其进行了标准化。PATCH 是一个不安全、不可幂等的,允许进行完整和部分更新以及对其他资源造成副作用的方法。

在实际应用中,如您所见,相较于 PUT,PATCH 更适合日常 Web 编程,用于更新资源。在 Ruby on Rails 中,它自然地对应于我们使用 update_attributes 更新记录的方式。

因此,PATCH 将成为 Rails 4.0 中更新的首选方法。

路由

这是一个重要的变更,但我们计划以向后兼容的方式进行变更。

当资源在 config/routes.rb 中声明时,例如,

resources :users

UsersController 中更新用户的操作在 Rails 4.0 中仍然是 update

Rails 4.0 中向 /users/:id 发出的 PUT 请求会像今天一样被路由到 update。因此,如果你有一个获取实际 PUT 请求的 API,它会有效。

不过,在 Rails 4.0 中,路由器还将 PATCH 请求路由到 /users/:id,即 update 操作。

因此,在 Rails 4.0 中,PUT 和 PATCH 都被路由到 update

表单

持久化资源的表单

form_for @user

在隐藏字段 “_method” 中获取“patch”。RFC 对 PATCH 请求中表示变更的方式故意含糊不清。提交表单完全有效,客户端和服务器必须简单地就更新资源的可接受方式达成一致。

让我强调一下,“_method” 修复程序是为了解决 Web 浏览器中的限制。正如你可能知道的那样,Rails 路由真正的 HTTP 方法。也就是说,实际的 PUT、DELETE,现在是 PATCH 请求被路由到它们各自的操作。

通用可用性

PATCH 请求可以在今天其他方法可用的所有位置使用。路由 DSL 中有一个 patch 宏,:via 理解符号 :patch。测试可以发出 PATCH 请求,请求对象响应 patch?,等等。详情请参见 原始提交(此处有一个重要的后续说明 here)。

我的 Web 服务器是否理解 PATCH?

是的,应该理解。我个人已经尝试过 Apache、nginx、Phusion Passenger、Unicorn、Thin 和 WEBrick。它们都可以直接理解 PATCH 请求。

此外,HTTP 客户端一般应该能够发出 PATCH 请求。例如,在 curl(1) 中,你会执行

curl -d'user[name]=wadus' -X PATCH https://:3000/users/1

鸣谢

我们想感谢 David Lee 对此做出的贡献以及在 讨论了数月 之后仍对这个话题充满兴趣的不懈耐心。

此外,我还想强调修复程序本身的质量。它非常出色:经过修订的代码、测试、所有文档、代码中的注释。一切都经过仔细而全面的更新。 范例修补程序