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


155

因此,我浏览了一些有关创建REST API的文章。其中一些建议使用所有类型的HTTP请求:like 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服务尚不甚了解。但是,仅通过常规或(包含方法名称和所有参数)接受JSON对象,然后也以JSON响应会不会更容易。我们可以轻松地通过PHP进行序列化/反序列化,并且无需处理不同的HTTP请求方法就可以对数据进行任何处理。POSTGETjson_encode()json_decode()

我想念什么吗?

更新1:

好的-在研究了各种API并学习了很多有关XML-RPCJSON-RPCSOAPREST的知识之后,我得出了这样的API合理的结论。实际上,堆栈交换实际上是在他们的站点上使用这种方法的,我确实认为这些人知道他们在做什么堆栈交换API


4
为什么要强制使用JSON有效负载?如果没有JSON,并且是普通的旧GET,该怎么办?
Mike DeSimone

Answers:


200

的想法RE表象小号泰特Ť转让(BOT)是不是在可能的最简单的方法访问数据。

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

REST是一种有意义的数据访问方法。当您在REST中看到请求时,应该立即了解数据的情况。

例如:

GET: /cars/make/chevrolet

可能会返回雪佛兰汽车的清单。 好的REST api甚至可以在querystring中包含一些输出选项,例如?output=json?output=html,这将允许访问者决定信息应以哪种格式编码。

关于如何合理地一体化的数据类型为REST API比特思考后,我已经得出结论,最好的办法明确指定的数据类型是通过已存在的文件扩展名,例如.js.json.html,或.xml。缺少的文件扩展名将默认为默认格式(例如JSON);不支持的文件扩展名可能返回501 Not Implemented状态码

另一个例子:

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

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

现在我们需要讨论幂等问题。通常,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]

这种方法的问题是,是否/cars/oldest请求时间和delete发布时间之间添加了另一个项目。


3
@Andre是多种原因的结合:遵循HTTP准则意味着(当事情发生变化时)您(可能)会减少向后兼容性问题。通过POST使用html表单会警告用户多次提交相同的数据(这是为了防止非幂等事务);遵循明确的最佳实践是最佳实践。休息时并未考虑到特定的实现方式,因此您可以根据需要使用它。我建议您利用HTTP的所有错误代码和请求方法,但可以根据需要进行操作
zzzzBov 2011年

4
因此,此答案的问题(这是一个不错的答案,但不完整)是,它没有解决他问的主要问题:为什么要使用HTTP动词和URI而不是自定义JSON数据(也许是某种基于JSON的API调用语法)。您可以自定义JSON语法,以使其“立即……了解数据的变化”。您无法做的就是轻松地使用HTTP之上的内置功能和网络分层,就像使用遵循所有REST约定的API一样。当然,并不是我的回答是完美的;)
Merlyn Morgan-Graham

4
@Andre:Wiki条目使用的示例是身份验证,缓存和内容类型协商。现在,我正在考虑更多的事情,您也许可以将它们与RPC样式的接口一起使用,但是诱惑通常是从头开始实现您自己的系统,或者编写与现有系统的集成代码。使用REST,您可以使用内置集成,并在Web服务器上对其进行管理。这意味着更宽松的耦合,这意味着您必须减少实施,并且意味着您的应用程序将来可以更灵活地更改选项,从而减少代码和测试影响。
Merlyn Morgan-Graham

10
而不是DELETE:/ cars / oldest,如何获取:/ cars / oldest,然后是DELETE?这样,您就有两个单独的幂等命令。
尼尔

3
+1; 我同意这是一个很好的答案(为了娱乐和获利,我将再次讨论它)。POST: /cars/oldest代替DELETE并没有多大意义。POST: /cars/oldest/delete可能-这样,也许我想我更喜欢Neil的解决方案。直接删除优于其get-id-delete-id解决方案的唯一优势是原子性。在实施此类事情之前,我希望有一个无人为案的场景有明确的业务理由。您不需要在所有对象/ URL上都支持所有动词。
Merlyn Morgan-Graham

39

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

安全方法

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

幂等方法

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

资源


1
抱歉,PUT和DELETE等幂方法如何?它们会影响服务器及其数据的状态!
Mahmoud Al-Qudsi 2011年

27
@计算机:执行相同的PUT或相同的DELETE会导致相同的最终状态。就是“幂等”的意思。
伊格纳西奥·巴斯克斯

4
为了进一步说明:如果操作F的单个应用程序及其几个后续应用程序都返回相同的结果,则该操作是幂等的。更确切地说,当且仅当F(x)= F(F(x))时,F是幂等的。例如,“删除”是幂等的,因为当您一次删除一个项目或多次删除该项目时,结果是相同的:使用“删除第一个”应用程序仅删除一次该项目,而在删除第二个或第三个应用程序中什么也没有发生。
qartal

1
但是就创建而言,当您使用create命令创建新记录并再次发出同一命令时,(可能)会创建两个记录(尽管它们都反映相同的信息)。
qartal

qartal-您对幂等的函数定义应为'F(X)= F(X)F(X)'。短语的好方法。
Gerard ONeill

26

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


2
我有点头疼。这篇文章(lornajane.net/posts/2013/…)指出,该动词应来自HTTP请求,以便URI仅包含名词,这对我来说是一个小问题
icc97

9

你问

只通过普通的$ _POST接受JSON对象,然后也以JSON响应会不会更容易

REST上的Wikipedia :

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

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

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

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

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

你问

我想念什么吗?

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

另外,如果您使用的是真正的静态API,则可以了解很多基于HTTP构建的各种网络技术的知识。我将从身份验证开始。


8

关于使用扩展名定义数据类型。我注意到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  

4

我想念什么吗?

是。;-)

由于统一的界面约束而存在这种现象。REST喜欢使用现有的标准,而不是重新发明轮子。HTTP标准已经被证明具有高度的可扩展性(网络正在运行一段时间)。为什么我们要修复未损坏的东西?

注意:如果要使客户端与服务脱钩,统一接口约束很重要。它类似于为类定义接口以使它们彼此分离。Ofc。在这里,统一接口由HTTPMIME类型URIRDF链接数据vocabhydra vocab等标准组成。


2

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

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

为什么?

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

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

我使用PHP,所以我使用function_exists(我认为它叫做)。如果该功能不存在,我将抛出405(不允许使用方法)。


2

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也是如此。您可以删除十次,这与删除一次相同。

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

请访问网址以获取更多详细信息。 http://www.artima.com/lejava/articles/why_put_and_delete.html

更新:

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

请考虑以下示例:

a = 4;

a ++;

第一个示例是幂等的:无论我们执行该语句多少次,a始终为4。第二个示例不是幂等的。执行10次将导致与运行5次不同的结果。由于两个示例都在更改a的值,因此它们都是不安全的方法。


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

0

基本上REST是(wiki):

  1. 客户端-服务器架构
  2. 无国籍
  3. 可缓存性
  4. 分层系统
  5. 按需代码(可选)
  6. 统一的界面

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.