ChatGPT解决这个技术问题 Extra ChatGPT

REST API - 为什么使用 PUT DELETE POST GET?

所以,我浏览了一些关于创建 REST API 的文章。其中一些建议使用所有类型的 HTTP 请求:例如 PUT DELETE POST GET。例如,我们将创建 index.php 并以这种方式编写 API:

$method = $_SERVER['REQUEST_METHOD'];
$request = split("/", substr(@$_SERVER['PATH_INFO'], 1));

switch ($method) {
  case 'PUT':
    ....some put action.... 
    break;
  case 'POST':
    ....some post action.... 
    break;
  case 'GET':
    ....some get action.... 
    break;
  case 'DELETE':
    ....some delete action.... 
    break;
}

好的,理所当然 - 我对 Web 服务知之甚少(还)。但是,通过常规 POSTGET(包含方法名称和所有参数)接受 JSON 对象然后也以 JSON 响应不是更容易吗?我们可以通过 PHP 的 json_encode()json_decode() 轻松地序列化/反序列化,并对这些数据做任何我们想做的事情,而无需处理不同的 HTTP 请求方法。

我错过了什么吗?

更新 1:

好的 - 在研究了各种 API 并了解了很多关于 XML-RPCJSON-RPCSOAPREST 我得出的结论是这种类型的 API 是合理的。实际上堆栈交换在他们的网站上几乎使用这种方法,我认为这些人知道他们在做什么Stack Exchange API

为什么要强制使用 JSON 有效负载?如果没有 JSON,它是一个普通的旧 GET 怎么办?

j
jere

REpresentational State Transfer 的想法不是以最简单的方式访问数据。

您建议使用发布请求来访问 JSON,这是访问/操作数据的一种完全有效的方式。

REST 是一种有意义的数据访问方法。当您在 REST 中看到请求时,应该立即清楚数据发生了什么。

例如:

GET: /cars/make/chevrolet

很可能会返回一份雪佛兰汽车的清单。 一个好的 REST api 甚至可以在查询字符串中包含一些输出选项,例如 ?output=json?output=html,这将允许访问者决定信息应该以什么格式编码。

在考虑了如何合理地将数据类型合并到 REST API 中之后,我得出结论,明确指定数据类型的最佳方法是通过已经存在的文件扩展名,例如 .js.json.html.xml。缺少的文件扩展名将默认为任何默认格式(例如 JSON);不受支持的文件扩展名可能会返回 501 Not Implemented status code

另一个例子:

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }

很可能会在数据库中创建一个带有相关颜色的新雪佛兰马里布。我说可能是因为 REST api 不需要与数据库结构直接相关。它只是一个屏蔽接口,以便保护真实数据(将其视为数据库结构的访问器和修改器)。

现在我们需要讨论 idempotence 的问题。通常 REST 通过 HTTP 实现 CRUD。 HTTP 对请求使用 GETPUTPOSTDELETE

一个非常简单的 REST 实现可以使用以下 CRUD 映射:

Create -> Post
Read   -> Get
Update -> Put
Delete -> Delete

这个实现存在一个问题: Post 被定义为非幂等方法。这意味着后续调用相同的 Post 方法将导致不同的服务器状态。 Get、Put 和 Delete 是幂等的;这意味着多次调用它们应该会导致相同的服务器状态。

这意味着一个请求,例如:

Delete: /cars/oldest

实际上可以实现为:

Post: /cars/oldest?action=delete

然而

Delete: /cars/id/123456

如果您调用它一次,或者如果您调用它 1000 次,将导致相同的服务器状态。

处理删除 oldest 项的更好方法是请求:

Get: /cars/oldest

并使用结果数据中的 ID 发出 delete 请求:

Delete: /cars/id/[oldest id]

如果在请求 /oldest 和发出 delete 之间添加了另一个 /cars 项,则此方法会出现问题。


@Andre 这是多种原因的组合:遵循 HTTP 指南意味着当事情发生变化时,您(可能)会遇到更少的向后兼容性问题;通过 POST 使用 html 表单将警告用户多次提交相同的数据(这是为了防止非幂等事务);遵循明确定义的最佳实践是,嗯..最佳实践。 Rest 的定义并没有考虑到特定的实现,它允许您以您认为合适的方式使用它。我建议利用所有 HTTP 的错误代码和请求方法,但你可以随心所欲地这样做
所以这个答案的问题(这是一个不错的答案,但不完整)是它没有解决他问的主要问题:为什么你要使用 HTTP 动词和 URI 而不是自定义 JSON 数据(也许是某种基于 JSON 的 API 调用语法)。您可以制作自定义 JSON 语法,使其“立即......明显地看到数据正在发生的事情”。您不能像使用遵循所有 REST 约定的 API 一样轻松使用 HTTP 之上的内置设施和网络分层。当然,并不是说我的答案是完美的;)
@Andre:wiki 条目使用的示例是身份验证、缓存和内容类型协商。现在我正在考虑更多,您也许可以将这些与 RPC 样式接口一起使用,但诱惑通常是从头开始实现您自己的系统,或者编写与现有系统的集成代码。借助 REST,您可以使用内置集成,并在 Web 服务器上对其进行管理。这意味着更松散的耦合,这意味着您必须实现更少,并且意味着您的应用程序在将来更改选项时更加灵活,代码和测试影响更小。
而不是 DELETE:/cars/oldest,GET:/cars/oldest 后跟 DELETE 怎么样?这样,您就有了两个独立的幂等命令。
+1;我同意这是一个很好的答案(为了乐趣和利润,我会再次讨论它)。 POST: /cars/oldest 代替 DELETE 没有多大意义。像 - POST: /cars/oldest/delete 这样的东西可能,但我认为我更喜欢 Neil 的解决方案。与他的 get-id-delete-id 解决方案相比,直接删除的唯一优势是原子性。在我实施这样的事情之前,我想要一个明确的商业理由和一个非人为的场景。您不需要支持所有对象/url 上的所有动词。
M
Mike DeSimone

这是一个安全性和可维护性问题。

安全方法

只要有可能,您应该使用“安全”(单向)方法,例如 GET 和 HEAD,以限制潜在的漏洞。

幂等方法

只要有可能,您应该使用“幂等”方法,例如 GET、HEAD、PUT 和 DELETE,它们不会产生副作用,因此更不容易出错/更容易控制。

Source


抱歉,但是 PUT 和 DELETE 幂等方法如何?它们会影响服务器及其数据的状态!
@Computer:执行相同的 PUT 或相同的 DELETE 会导致相同的最终状态。这就是“幂等”的意思。
为了更清楚地说明:操作 F 是幂等的,如果它的单个应用程序和它的几个后续应用程序都返回相同的结果。更准确地说,F 是幂等的当且仅当 F(x)=F(F(x))。例如,Delete 是幂等的,因为当您删除一个项目一次,或者多次删除它时,结果是相同的:该项目在第一个删除应用程序中被删除一次,而在删除第二个或第三个应用程序中没有任何反应。
但是在创建方面,当您使用创建命令创建新记录并再次发出相同的命令时,(可能)创建了两条记录(尽管两者都反映了相同的信息)。
qartal——你对幂等的函数定义应该是'F(X) = F(X)F(X)'。很好的方式来表达它。
N
Neil

简而言之,REST 强调名词而不是动词。随着您的 API 变得越来越复杂,您会添加更多的东西,而不是更多的命令。


我很难理解这一点。这篇文章 (lornajane.net/posts/2013/…) 说动词应该来自 HTTP 请求,以便 URI 应该只包含名词,这对我来说有点清楚
M
Merlyn Morgan-Graham

您问:

通过普通 $_POST 接受 JSON 对象然后也以 JSON 响应不是更容易吗

来自 REST 上的 Wikipedia:

RESTful 应用程序最大限度地利用预先存在的、定义良好的接口和所选网络协议提供的其他内置功能,并最大限度地减少在其之上添加新的应用程序特定功能

从我所看到的(很少)来看,我相信这通常是通过最大限度地利用现有 HTTP 动词并为您的服务设计一个尽可能强大且不言而喻的 URL 方案来实现的。

不鼓励自定义数据协议(即使它们构建在标准协议之上,例如 SOAP 或 JSON),并且应该最小化以最好地符合 REST 意识形态。

另一方面,基于 HTTP 的 SOAP RPC 鼓励每个应用程序设计人员定义一个新的、任意的名词和动词词汇表(例如 getUsers()、savePurchaseOrder(...)),通常覆盖在 HTTP 'POST' 动词上。这忽略了 HTTP 的许多现有功能,例如身份验证、缓存和内容类型协商,并可能让应用程序设计人员在新词汇表中重新发明许多这些功能。

您正在使用的实际对象可以是任何格式。这个想法是尽可能多地重用 HTTP 来公开用户想要对这些资源执行的操作(查询、状态管理/突变、删除)。

您问:

我错过了什么吗?

还有很多关于 REST 和 URI 语法/HTTP 动词本身的知识。例如,有些动词是幂等的,有些则不是。我在您的问题中没有看到任何关于此的内容,因此我没有费心尝试深入研究。其他答案和维基百科都有很多很好的信息。

此外,如果您使用的是真正的 RESTful API,您可以利用这些构建在 HTTP 之上的各种网络技术。我将从身份验证开始。


P
Pawel Cioch

关于使用扩展来定义数据类型。我注意到 MailChimp API 正在这样做,但我认为这不是一个好主意。

GET /zzz/cars.json/1

GET /zzz/cars.xml/1

我的想法听起来不错,但我认为“旧”方法更好——使用 HTTP 标头

GET /xxx/cars/1
Accept: application/json

此外,HTTP 标头对于跨数据类型通信要好得多(如果有人需要它)

POST /zzz/cars
Content-Type: application/xml     <--- indicates we sent XML to server
Accept: application/json          <--- indicates we want get data back in JSON format  

C
Community

我错过了什么吗?

是的。 ;-)

这种现象的存在是因为uniform interface constraint。 REST 喜欢使用已经存在的标准,而不是重新发明轮子。 HTTP 标准已经被证明是高度可扩展的(网络已经运行了一段时间)。我们为什么要修复没有损坏的东西?!

注意:如果您想将客户端与服务分离,统一接口约束很重要。它类似于为类定义接口以便将它们彼此分离。办公室。在这里,统一接口由 HTTPMIME typesURIRDFlinked data vocabshydra vocab 等标准组成......


H
HumbleWebDev

良好的语义在编程中很重要。

使用除 GET/POST 之外的更多方法会很有帮助,因为它会增加代码的可读性并使其更易于维护。

为什么?

因为您知道 GET 将从您的 api 中检索数据。您知道 POST 会将新数据添加到您的系统中。您知道 PUT 会进行更新。 DELETE 将删除行等,等等,

我通常构建我的 RESTFUL Web 服务,以便我有一个与方法名称相同的函数回调。

我使用 PHP,所以我使用 function_exists (我认为它被称为)。如果该函数不存在,我会抛出 405(不允许使用方法)。


B
Bimal Das

Bill Venners:在您题为“为什么 REST 失败”的博文中,您说我们需要所有四个 HTTP 动词——GET、POST、PUT 和 DELETE——并感叹浏览器供应商只需要 GET 和 POST。”为什么我们需要所有四个动词?为什么 GET 和 POST 还不够?

Elliotte Rusty Harold:HTTP 中有四种基本方法:GET、POST、PUT 和 DELETE。大部分时间都使用 GET。它用于任何安全且不会引起任何副作用的事物。 GET 能够被添加书签、缓存、链接到、通过代理服务器。这是一个非常强大的操作,非常有用的操作。

相比之下,POST 可能是最强大的操作。它可以做任何事情。对于可能发生的事情没有限制,因此,您必须非常小心。你没有给它添加书签。你不缓存它。你不预先获取它。在不询问用户的情况下,您不会对 POST 做任何事情。你想这样做吗?如果用户按下按钮,您可以发布一些内容。但是您不会查看页面上的所有按钮,然后开始随机按下它们。相比之下,浏览器可能会查看页面上的所有链接并预获取它们,或者预获取他们认为接下来最有可能被关注的链接。事实上,一些浏览器和 Firefox 扩展程序以及其他各种工具都曾尝试过这样做。

PUT 和 DELETE 位于 GET 和 POST 之间。 PUT 或 DELETE 与 POST 的区别在于 PUT 和 DELETE 是*幂等的,而 POST 不是。如有必要,可以重复 PUT 和 DELETE。假设您正在尝试将新页面上传到站点。假设您想在 http://www.example.com/foo.html 创建一个新页面,因此您键入内容并将其放在该 URL 中。服务器在您提供的那个 URL 上创建该页面。现在,让我们假设由于某种原因您的网络连接中断。您不确定,请求是否通过?可能网络很慢。可能是代理服务器问题。因此,再试一次或再试一次是完全可以的——你喜欢多少次都可以。因为将同一个文档放置到同一个 URL 十次与放置一次没有什么不同。 DELETE 也是如此。您可以 DELETE 十次,这与删除一次相同。

相比之下,POST 每次都可能导致不同的事情发生。想象一下,您正在通过按下购买按钮从在线商店结账。如果您再次发送该 POST 请求,您最终可能会再次购买购物车中的所有物品。如果您再次发送它,您已经购买了第三次。这就是为什么浏览器必须非常小心地在未经用户明确同意的情况下重复 POST 操作,因为如果执行两次 POST 可能会导致两件事发生,如果执行三次可能会导致三件事发生。使用 PUT 和 DELETE,0 个请求和 1 个请求有很大区别,但 1 个请求和 10 个请求没有区别。

请访问网址了解更多详情。 http://www.artima.com/lejava/articles/why_put_and_delete.html

更新:

幂等方法 幂等 HTTP 方法是一种可以多次调用而不会产生不同结果的 HTTP 方法。该方法是否只被调用一次或十次都没有关系。结果应该是一样的。同样,这仅适用于结果,而不适用于资源本身。这仍然可以被操纵(如更新时间戳,只要此信息未在(当前)资源表示中共享)。

考虑以下示例:

a = 4;一个++;

第一个例子是幂等的:无论我们执行多少次这条语句,a总是4。第二个例子不是幂等的。执行 10 次将产生与运行 5 次不同的结果。由于这两个示例都在更改 a 的值,因此它们都是非安全方法。


关于新页面的示例,不应该以这种方式使用 POST,而 PUT 用于更新?创建一个新页面是一个每次都会产生新结果的过程,而相同的编辑可能会被重复任意次数,每次都会产生相同的结果。不过,很好的措辞和解释。
M
M-A-X

基本上 REST 是 (wiki):

客户端-服务器架构 无状态 可缓存性 分层系统 按需代码(可选) 统一接口

REST 不是协议,它是原则。不同的 uris 和方法 - 所谓的最佳实践。