PUT 和 DELETE HTTP 请求方法有啥用处?

Posted

技术标签:

【中文标题】PUT 和 DELETE HTTP 请求方法有啥用处?【英文标题】:What is the usefulness of PUT and DELETE HTTP request methods?PUT 和 DELETE HTTP 请求方法有什么用处? 【发布时间】:2012-08-21 23:32:13 【问题描述】:

我从未使用过 PUT 或 DELETE HTTP 请求方法。我倾向于在系统状态(我的应用程序或网站)可能不受影响(如产品列表)时使用 GET,并在受影响时(如下订单)使用 POST。这两个不是总是足够的,还是我错过了什么?

【问题讨论】:

PUT/DELETE 更容易编码,但更难设置(安全方面 - vhost/apache 目录)。我的拙见......你可以没有这些生活。 @Najzero 是的,没有他们我非常高兴:) 但需要一些关于他们为什么在那里的答案?读过一些东西,但不能抄袭 另见***.com/questions/630453/… - 接受的答案对 POST 与 PUT 进行了很好的讨论 【参考方案1】:

DELETE 用于删除请求资源:

DELETE 方法请求源服务器删除由 Request-URI 标识的资源。此方法可能会被源服务器上的人工干预(或其他方式)覆盖。客户端不能保证操作已经执行,即使源服务器返回的状态码表明操作已经成功完成……

PUT 用于在服务器上放置或更新资源:

PUT 方法请求将封闭的实体存储在提供的 Request-URI 下。如果 Request-URI 引用了一个已经存在的资源,封闭的实体应该被认为是在源服务器上的一个修改版本。如果 Request-URI 不指向现有资源,并且该 URI 能够被请求用户代理定义为新资源,则源服务器可以使用该 URI 创建资源……

如需完整规格,请访问:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Since current browsers unfortunately do not support any other verbs than POST and GET in HTML forms,您通常无法充分利用 HTTP 与他们(尽管您仍然可以通过 javascript 劫持他们的提交)。 HTML 表单中不支持这些方法导致 URI 包含动词,例如

POST http://example.com/order/1/delete

甚至更糟

POST http://example.com/deleteOrder/id/1

通过 HTTP 有效地隧道化 CRUD 语义。但是动词从来都不是 URI 的一部分。相反,HTTP 已经通过 HTTP 方法提供了对资源(例如订单)进行 CRUD 的机制和语义。 HTTP 是一种协议,而不仅仅是一些数据隧道服务。

所以要删除网络服务器上的资源,你需要调用

DELETE http://example.com/order/1

并且要更新它你会调用

PUT http://example.com/order/1

并在 PUT 正文中提供更新的资源表示供网络服务器随后应用。

因此,如果您正在为REST API 构建某种客户端,您可能会使其发送 PUT 和 DELETE 请求。这可能是在浏览器中构建的客户端,例如通过 JavaScript 发送请求,或者它可能是在服务器上运行的某个工具等。

更多详情请访问:

http://martinfowler.com/articles/richardsonMaturityModel.html Are the PUT, DELETE, HEAD, etc methods available in most web browsers? Why are there no PUT and DELETE methods in HTML forms Should PUT and DELETE be used in forms? http://amundsen.com/examples/put-delete-forms/ http://www.quora.com/HTTP/Why-are-PUT-and-DELETE-no-longer-supported-in-HTML5-forms

【讨论】:

浏览器可以使用 JavaScript 发送 PUT 和 DELETE! @Joe 是的,但 HTML 表单方法没有。只要不支持开箱即用,您就必须经过努力才能使其发挥作用。这是浏览器供应商的主要失败之一。 当然不是,表单是为 POST 和 GET 设计的。那是在设计 HTML 中。说不支持 PUT 和 DELETE 是不正确的。浏览器实现 HTML 和 HTTP。 浏览器显示一个空白页面,除非您编写一些 HTML。是的,也许我们不得不不同意。不同意也没关系! 例如,DELETE 可以做一些事情,比如使 URI 的缓存版本无效。使用基于 POST 的 API,您使用的任何代理要么必须知道您的 API 做什么(不好),要么完全关闭(也不好)。这就是我们使用标准的原因。 :) (尽管如果表单能够将 DELETE 绑定到提交按钮,那当然会很好。)【参考方案2】:

使用 HTTP 请求动词,如 GET、POST、DELETE、PUT 等...使您能够构建 RESTful Web 应用程序。在这里阅读:http://en.wikipedia.org/wiki/Representational_state_transfer

查看此示例的好处的最简单方法是查看此示例。 每个 MVC 框架都有一个 Router/Dispatcher 将 URL-s 映射到 actionController。 所以像这样的 URL:/blog/article/1 会调用 blogController::articleAction($id); 现在这个路由器只知道 URL 或/blog/article/1/

但是,如果路由器知道整个 HTTP 请求对象而不仅仅是 URL,他就可以访问 HTTP 请求动词(GET、POST、PUT、DELETE...),以及有关当前 HTTP 请求的许多其他有用的东西。

这将使您能够配置应用程序,以便它可以接受相同的 URL 并根据 HTTP 请求动词将其映射到不同的 actionController。

例如:

如果您想检索第 1 条,您可以这样做:

GET /blog/article/1 HTTP/1.1

但如果你想删除第 1 条,你会这样做:

DELETE /blog/article/1 HTTP/1.1

请注意,两个 HTTP 请求具有相同的 URI,/blog/article/1,唯一的区别是 HTTP 请求动词。并且基于那个动词,你的路由器可以调用不同的 actionController。这使您能够构建整洁的 URL-s。

阅读这两篇文章,它们可能会对你有所帮助:

Symfony 2 - HTTP Fundamentals

Symfony 2 - Routing

这些文章是关于 Symfony 2 框架的,但它们可以帮助您弄清楚 HTTP 请求和响应是如何工作的。

希望这会有所帮助!

【讨论】:

这个答案最好地解释了描述 HTTP 动词的重要性并与真正的 RESTful 服务及其优势保持一致。如果您不使用 HTTP DELETE,那么您可能在控制器中有 (2) 个 POST 操作:Create 为 1,Delete 为 1。如果您这样做,您的下一个搜索将是“如何在单个控制器中拥有多个 Post 操作”:P。并不是说这很糟糕,但是您失去了通过动词操作实现唯一资源的能力,而不必在 URI 中显式提供操作名称。【参考方案3】:

虽然我冒着不受欢迎的风险,但我说它们现在没用了

我认为它们在过去是很好用的,例如 DELETE 告诉服务器删除在提供的 URL 中找到的资源,而 PUT(及其同级 PATCH)告诉服务器以幂等方式进行更新。

随着事情的发展,URL 变得虚拟(例如,参见 url 重写)使得资源失去了真正的文件夹/子文件夹/文件的初始含义,因此 HTTP 协议方法(GET、 POST、PUT/PATCH、DELETE)丢失了轨道。

举个例子:

/api/entity/list/idGET /api/entity/id /api/entity/add/idPOST /api/entity /api/entity/edit/idPUT /api/entity/id /api/entity/delete/idDELETE /api/entity/id

左边没有写 HTTP 方法,本质上没关系(POST 和 GET 就足够了),右边使用了适当的 HTTP 方法。

右侧看起来优雅、干净、专业。想象一下,现在您必须维护一个一直在使用优雅 API 的代码,并且您必须搜索删除调用的完成位置。您将搜索 "api/entity" 并在结果中查看哪个正在执行 DELETE。或者更糟糕的是,你有一个初级程序员错误地将 PUT 切换为 DELETE 并且 URL 发生了同样的事情。

在我看来,将动作动词放在 URL 中比为该动作使用适当的 HTTP 方法具有优势,即使它不是那么优雅。如果您想查看删除调用的位置,只需搜索 "api/entity/delete" 即可立即找到。

在没有整个 HTTP 方法数组的情况下构建 API 可以更容易地在之后使用和维护

【讨论】:

合理的论点,但动作专用方法的语义胜过通过 URL 命名方法的“便利性”。如果您使用 POST 或事件 GET 来执行 DELETE,那么您只是在滥用 HTTP 方法,这些方法分别明确定义为创建新资源和检索现有资源的方法。使用集成测试确保初级开发人员无法更改 API 行为。我通常对那些让开发人员“方便”的事情保持警惕——它们通常是代码异味或低质量开发的第一个迹象。 Url重写也不会改变协议定义?? @ChrisHalcrow 同意你的观点,但程序员是人,而不是机器人,他们倾向于方便。我喜欢标准、定义等……我喜欢遵循它们,但前提是它们实际上是合理的 对操作使用标准动词绝对是“合理实用的”。理解/习惯 GET 表示 'retrieve'(包含 ID 参数)或 'list'(如果不是), POST means add (它甚至可以合理地接受POST 表示“更新”或“更新”,但仅作为数据的完全覆盖)。并且 DELETE 是不言自明的。我看不出有什么不切实际的。例如,如果您以某种方式生成或构建一个 RESTFUL API,则默认情况下,工具更有可能使用正确的动词为 URL 生成一个相当标准的“RESTFUL”结构。 我建议区分路由命名(URL)和操作名称。因此,可以将 DELETE /api/entity/id 指定为调用该方法的 route,并且该操作可以封装在任一工作单元中,例如myEntity.Delete(),或在方法DeleteEntity() 中。然后它必须对任何人都清晰可见。 我遇到的主要问题是您说 PUT 和 DELETE 都没有用。该标准规定 GET 应返回已识别的资源。 POST 是一个非幂等操作,其中生成的资源应该是 POST 中使用的 Uri 的从属。两者都不应该用于删除。此外,没有逻辑链接我可以看到 URL 重写应该使 PUT 或 DELETE 变得多余。 URL 重定向只是转发到应该遵守 HTTP 标准的 URI。良好的“RESTFUL”设计的主要概念是在 API 实现中尊重 HTTP 标准的预期。【参考方案4】:

安全方法:获取资源/不修改资源幂等:如果多次请求,资源状态不会改变不安全方法: 在资源中创建或更新资源/修改非幂等: 如果多次请求,资源状态会发生变化

根据您的要求:

1) 为了安全和幂等操作(获取资源)使用 --------- GET METHOD 2) 对于不安全和非幂等操作(插入资源)使用--------- POST METHOD 3) 对于不安全和幂等操作(更新资源)使用--------- PUT METHOD 3) 对于不安全和幂等操作(删除资源)使用--------- DELETE METHOD

【讨论】:

【参考方案5】:

查看@Gordon 接受的答案,关键点很简单:

PUT 和 DELETE 是具有含义的特定动词,指示服务器执行特定操作以及应如何处理指令。

OK 标准和语义很好,但如果我只想以某种方式运行代码从数据库中删除某些内容,那么 DELETE 对我来说真正有用吗?

如果我们说,“好吧,但我更容易通过向我的 URI 发出一个具有路径 /api/entity/delete/id 的 GET 来执行删除操作(正如 @Bogdan 的回答中所建议的那样)。好吧,让我们看看在 GET 的定义中:

GET 方法意味着检索任何信息(以 entity) 由 Request-URI 标识

来源 - W3C 标准 - https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

如果您将GET 用于DELETE,那么根据其标准定义,您显然是在滥用该方法

好吧,让我们进一步说“好的,但这并不重要,因为对于开发人员来说,在某处使用 GET 方法读取 URI 并读取 /api/entity/delete/id 而不是使用删除资源的 DELETE 方法更实用与检索的 GET 方法相同的签名,以便开发人员了解这是为了删除。让我们考虑一个结构良好的 DELETE 方法签名(示例适用于 .NET Core 5):

// DELETE: api/TodoItems/5
[HttpDelete("id")]
public async Task<IActionResult> DeleteTodoItem(long id)

这不会响应获取请求,(例如,在调用 API 时意外删除而不是检索会受到更多保护 - 开发人员必须显式执行删除请求以API)。而且我们有一个非常清晰、结构良好且命名的 API 操作,开发人员甚至自动化工具都可以清楚地发现它(例如,开发人员现在可以专门搜索代码中任何出现的 DELETE,或者搜索清楚的方法名称)表示删除)。更重要的是,这种模式符合普遍接受的“RESTFUL”API 标准,应该使 API 更广泛地被开发人员(以及可能的任何自动化工具)识别和解释。

好的,这很好,但是将其设为 DELETE 的真正区别是什么?为什么还要使用 DELETE 而不是 GET?我的操作是从数据库中删除一些东西,我的网络服务器为什么要关心? OK,我们来想想DELETE的定义:

9.7 DELETE - DELETE 方法请求源服务器删除由 Request-URI 标识的资源。这种方法可能是 被原点上的人为干预(或其他方式)覆盖 服务器。

所以现在,如果我们指定删除,我们有可能在服务器上出现特定行为,这可能允许通过手动或自动干预来撤销删除操作。在特定用例中,这可能很重要。

好吧,那么 DELETE 对我有用,但为什么要使用 PUT?例如,如果我只是创建一个使用 POST 的“upsert”方法,如果资源存在则更新资源,如果不存在则创建它会更方便

我个人通常在实现对数据库进行操作的 API 时执行此操作,尽管 PUT 也有特定含义,即它具体表示资源的更新,而 POST 表示创建,所以使用 POST 来创建和更新是反标准的。我自己的观点是,当我通常认为 upsert 功能的实用性比严格使用正确的动词来添加与插入更重要时,REST API 是一种情况,但我可能会在这里遗漏一些东西。

在 REST api 之外使用 PUT 对于实际目的可能更重要,例如,如果我们正在执行更新操作,其中服务器可以通过了解资源已更新来潜在地清除任何缓存(这更重要例如,如果我们的资源是一个完整的文档)。在 RESTful API 中使用 PUT 进行更新操作时,可能会有一些我没有考虑过的实际优势。

POST 的标准定义声明 POST 成功响应应该是 201(已创建),而不仅仅是通用的“200 OK”,以便我们能够正确解释资源创建显式成功。该响应不适用于更新操作,但标准中没有为响应代码指定“必须”。开发人员使用 POST 进行 upsert 并在成功时返回 200(OK)当然很常见,无论是创建还是更新。

PUT 的标准更为严格,并指定在尝试更新时任何意外创建的资源都必须通过 201 响应代码来指示。如果指定 URI 中不存在现有资源,则可能发生这种情况。该标准解释说,如果我们使用 PUT,我们会得到更清晰的反馈,说明我们尝试更新操作的结果是否符合我们的预期。

来自 W3C 标准:

[如果 put] 不指向现有资源,并且该 URI 是 能够被请求用户定义为新资源 代理,源服务器可以使用该 URI 创建资源。如果一个 创建新资源,源服务器必须通知用户代理 通过 201(已创建)响应。如果修改了现有资源, 应该发送 200 (OK) 或 204 (No Content) 响应代码 表示请求成功完成。

【讨论】:

【参考方案6】:

当您需要更改资源时,使用PUT 方法。资源,它已经是资源集合的一部分。这里需要注意的一点是PUT 方法修改整个资源,而PATCH 方法用于修改资源或数据的必要部分。

删除

顾名思义,DELETE请求方法用于删除指定资源。它请求源服务器删除由 Request-URL 标识的资源。

我希望这个简单的定义有所帮助。

【讨论】:

以上是关于PUT 和 DELETE HTTP 请求方法有啥用处?的主要内容,如果未能解决你的问题,请参考以下文章

HTTP方法GET,POST,PUT和DELETE有啥区别

REST模式中HTTP请求方法(GET,POST,PUT,DELETE)

HTTP协议六种请求方法,get,head,put,delete,post有什么区别

http中的put,delete等请求为啥不安全

nginx proxy_pass基于请求方法是POST,PUT还是DELETE

Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格)