【问题标题】: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 是的,没有他们我非常高兴:) 但需要一些关于他们为什么在那里的答案?读过一些东西,但不能抄袭
  • 另见stackoverflow.com/questions/630453/… - 接受的答案对 POST 与 PUT 进行了很好的讨论

标签: http httprequest


【解决方案1】:

DELETE 用于删除请求资源:

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

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

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

如需完整规格,请访问:

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 发送请求,或者它可能是在服务器上运行的某个工具等。

更多详情请访问:

【讨论】:

  • 浏览器可以使用 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/{id}GET /api/entity/{id}
  • /api/entity/add/{id}POST /api/entity
  • /api/entity/edit/{id}PUT /api/entity/{id}
  • /api/entity/delete/{id}DELETE /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 标识的资源。

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

      【讨论】:

        猜你喜欢
        • 2013-08-26
        • 1970-01-01
        • 2015-05-17
        • 2010-10-28
        • 2010-09-11
        • 1970-01-01
        相关资源
        最近更新 更多