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_at
和 updated_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)。
是的,应该理解。我个人已经尝试过 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 对此做出的贡献以及在 讨论了数月 之后仍对这个话题充满兴趣的不懈耐心。
此外,我还想强调修复程序本身的质量。它非常出色:经过修订的代码、测试、所有文档、代码中的注释。一切都经过仔细而全面的更新。 范例修补程序。