首页  >  文章  >  REST 和 HTTP 语义

REST 和 HTTP 语义

百草
百草原创
2024-09-11 14:18:20977浏览

Roy Fielding 创建了 REST 作为他的博士论文。 

REST 和 HTTP 语义

读完后,我会将其归结为三个基本要素:

  1. 描述对象状态的文档

  2. 在系统之间来回传输对象状态的传输机制

  3. 对状态执行的一组操作

虽然 Roy 只专注于 HTTP,但我不明白为什么不能使用其他传输方式。以下是一些示例:

  • 安装 WebDAV 共享(WebDAV 是 HTTP 扩展,因此仍使用 HTTP)。将电子表格(.xls、.xlsx、.csv、.ods)复制到已安装的文件夹中,其中每一行都是新的/更新的状态。复制到共享的行为表示更新插入操作,文件名表示数据类型,列是字段。服务器以(文档名称)-status.(文档后缀)进行响应,它提供每行的键、状态以及可能的错误消息。在这种情况下,请求数据并没有多大意义。

  • 使用 gRPC。传输的对象是文档,HTTP 是传输,远程方法的名称是操作。数据可以提供和请求。

  • 使用 FTP。 与 WebDAV 类似,它是基于文件的。 PUT 命令是更新插入,GET 命令是请求。 GET 仅提供文件名,因此它通常提供指定类型的所有数据。可以允许使用特殊文件名来指示硬编码过滤器以获取数据子集。

每当我在野外看到 REST 实现时,它们通常不遵循基本的 HTTP语义学,我从未见过对此给出任何解释,只是一堆不同的意见。我发现这些都没有引用 RFC。大多数人似乎认为:

  • POST = 创建

  • PUT = 更新整个文档

  • PATCH = 更新文档的一部分

  • GET = 检索整个文档

这与 HTTP 关于 POST 和 PUT 的规定相反:

  • PUT 是“创建”或“更新”。 GET 通常会返回上次 PUT 的内容。如果 PUT 创建,它必须返回 201 Created。如果 PUT 更新,它必须返回 200 OK 或 204 No Content。 RFC 建议 PUT 的 200 OK 内容应该是操作的状态。我认为就 SQL 而言,从 select 语句返回新行是可以的。这样做的优点是,任何生成的列都会返回给调用者,而无需执行单独的 GET。

  • POST 根据资源自身的语义处理资源。较旧的 RFC 表示 POST 适用于资源的下属。所有版本都给出了将文章发布到邮件列表的示例;所有版本都说,如果创建了资源,则应返回 201 Created。

我认为 POST 的真正含义是:

  • 除创建、全部/部分更新或删除之外的任何数据操作

  • 任何非数据操作的操作,例如:

  • 执行全文搜索与短语匹配的行。

  • 生成要在地图上显示的 GIS 对象。

该词必须表示您的仅当您按照规定执行时,实现才符合 HTTP。仅使用 PUT 进行更新显然不会破坏任何内容,只是因为它不符合 RFC 标准。如果您提供处理发送/接收数据的所有细节的客户端,那么使用什么动词对于客户端的用户来说并不重要。

我是那种想要一个理由的人不遵循 RFC。我从来不理解在 REST API 中将创建与更新分开的重要性,就像在 Web 应用程序中一样。想想日历约会、笔记、联系人等手机应用程序:

  • “创建”点击加号图标,它会显示一个带有空值或默认值的新表单。

  • “更新”正在选择一个对象并点击铅笔图标,这将显示包含当前值的条目表单。

  • 一旦条目表单出现,它就会显示在字段验证方面的工作方式完全相同。

那么为什么 REST API 和 Web 前端与手机应用程序有任何不同呢?如果电话用户获得用于“创建”和“更新”的相同数据输入表单有帮助,那么它对 API 和网络用户是否也同样有帮助?

如果您决定使用 PUT 作为“创建”或“更新”,并且您使用 SQL 作为存储,大多数供应商都有某种类型的更新插入查询。不幸的是,这无助于决定何时返回 200 OK 或 201 Created。您必须查看驱动程序在执行 DML 查询时提供的信息,以找到区分更新插入的插入和更新的方法,或使用其他查询策略。 

一个简单的示例是执行更新集...其中 pk 列 = pk 值。如果一行受到影响,则该行存在并已更新;否则,该行不存在,需要插入。在 Postgres 上,您可以利用 RETURNING 子句,它实际上可以返回任何内容,而不仅仅是行数据,如下所示:

SQL VALUES (...) ON CONFLICT() DO UPDATE SET ( ...) 返回 (SELECT COUNT() FROMWHERE=) 存在" data-lang="text/x-sql" style="box-sizing: border-box;">1

INSERT INTO <table>
VALUES (...)
ON CONFLICT(<pk column>) DO
UPDATE SET (...)
RETURNING (SELECT COUNT(<pk column>) FROM <table> WHERE <pk column> = <pk value>) exists

这样做的天才在于:

  • RETURNING 子句中的子查询首先执行,因此它会在执行 INSERT ON CONFLICT UPDATE 查询之前确定该行是否存在。查询的结果是名为“exists”的列,如果该行在查询之前存在,则该列为 1。执行,如果没有执行,则返回 0。

  • RETURNING 子句还可以返回行的列,包括未提供的任何生成内容。

您只需弄清楚如何处理是否需要插入或更新,并进行一个简单的抽象,您的所有 PUT 都可以调用它来处理 200 OK 或 201 Created。

使用的一个很好的好处PUT 的目的是,一旦您看到 POST,您就确定它不是检索或持久性,相反,您知道搜索 POST 来查找任何不是检索或持久性操作的代码。

我认为按照 RFC 中的描述使用 PUT 和 POST 的好处超过了人们以不符合 RFC 的方式使用它们的任何原因。

以上是REST 和 HTTP 语义的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn