看到 10 多年后没有答案真正说明如何在 REST 架构中设计 OP 中要求的这种东西,我感到有点难过,因此我觉得现在有必要这样做。
首先,什么是 REST?!首字母缩略词 REST 或 ReST 代表“Representational State Transfer”,并以某种表示格式定义资源状态的交换。表示格式趋向于协商的媒体类型。在表示格式的情况下,application/html
可能是在浏览器中呈现的 HTML 格式的文本内容流,可能是在应用一些样式表格式以将某些元素定位在某些位置之后。
REST 原则上是我们都知道的可浏览 Web 的概括,尽管它针对各种应用程序而不仅仅是浏览器。因此,通过设计,适用于 Web 的相同概念也适用于 REST 架构。诸如如何以“RESTful”方式实现某事的问题围绕回答如何在 Web 页面上实现某事然后将相同的概念应用到应用程序层的问题来解决。
基于 Web 的计算器通常从一些“页面”开始,允许您在将输入的数据发送到服务器之前输入一些值进行计算。在 HTML 中,这通常是通过 HTML<form>
元素来实现的,这些元素教客户端设置可用参数、发送请求的目标位置以及发送输入数据时应用的表示格式。这可以看起来像这样:
<html>
<head>
...
</head>
<body>
<form action="/../someResource" method="post" enctype="application/x-www-form-urlencoded">
<label for="firstNumber">First number:</label>
<input type="number" id="firstNumber" name="firstNumber"/>
<label for="secondNumber">Second number:</label>
<input type="number" id="secondNumber" name="secondNumber"/>
<input type="submit" value="Add numbers"/>
</form>
</body>
</html>
上面的示例 ie 声明有两个输入字段可以由用户或其他自动机填写,并且在调用提交输入元素时,浏览器负责将输入数据application/x-www-form-urlencoded
格式化为发送的表示格式POST
在这种情况下,通过指定的 HTTP 请求方法到提到的目标位置。如果我们进入1
输入firstNumber
字段并2
进入secondNumber
输入字段,浏览器将生成一个表示firstNumber=1&secondNumber=2
并将其作为实际请求的正文有效负载发送到目标资源。
因此,向服务器发出的原始 HTTP 请求可能如下所示:
POST /../someResource
Host: www.acme.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Accept: application/html
firstNumber=1&secondNumber=2
服务器可以执行计算并使用包含计算结果的另一个 HTML 页面进行响应,因为请求表明客户端理解这种格式。
正如 Breton 已经指出的那样,没有“RESTful” URL 或 URI 这样的东西。URI/URL 是它自己的东西,不应该向客户端/用户传达任何含义。在上面的计算器示例中,用户根本不感兴趣将数据发送到哪里,只对触发提交输入字段时发送请求感兴趣。服务器应该已经提供了执行任务所需的所有必需信息。
浏览器也可能不知道该请求实际上是在为计算器提供一些输入参数,它也可能是某种订单表单,它只返回下一个表单表示以继续订购过程或某种完全不同的类型资源。在这种情况下,它只是执行 HTML 规范要求的内容,它并不关心服务器实际在做什么。这个概念使浏览器能够使用相同的表示格式来执行各种操作,例如从您喜欢的在线商店订购一些东西、与您最好的朋友聊天、登录在线帐户等等。
某些元素的可供性,例如在通常呈现为按钮的提交输入字段案例中,定义了您应该使用它做什么。对于按钮或链接,它基本上会告诉您单击它。其他元素可能传达不同的启示。这种可供性也可以通过链接关系来表达,即带preload
注释的链接基本上告诉客户端它已经可以在后台加载链接资源的内容,因为用户很可能接下来会抓取该内容。这样的链接关系当然应该标准化或遵循Web 链接定义的关系类型的扩展机制。
这些是在 Web 上使用的基本概念,也应该在 REST 架构中使用。根据“Uncle Bob”Robert C. Martin的说法,架构是关于意图的,REST 架构背后的意图是将客户端与服务器分离,以允许服务器在未来自由发展,而不必担心它们会破坏客户端。不幸的是,这需要大量的纪律,因为很容易引入耦合或添加快速修复解决方案来完成工作并继续前进。正如 Jim Webber 在 REST 架构中指出的那样,作为服务提供商,您应该尝试设计一个类似于 70 年代基于文本的计算机游戏的域应用程序协议,客户将一直执行该协议,直到他们到达流程的末尾。
不幸的是,许多所谓的“REST”API 在现实中所做的一切都是如此。您会看到在 API 特定的外部文档中指定的主要基于 JSON 的数据的交换,通常很难动态地动态集成。请求需要的格式也被硬编码到外部文档中,这导致大量实现解释 URI 以返回预定义的类型而不是使用一些预先协商好的通用表示格式。这可以防止服务器发生变化,因为客户端现在期望接收预定义 URI 的某种数据格式(注意不是表示格式!)。这种自定义数据格式交换进一步阻止了客户端与其他 API 交互,因为“数据格式”通常是针对特定 API 的。我们从过去的 RPC 技术中知道这个概念,例如 Corba、RMI 或 SOAP,我们谴责它们在某种程度上是邪恶的,尽管最近 Peppol 再次使用它,将 AS2 替换为 AS4 作为默认传输协议。
关于提出的实际问题,将数据作为 csv 文件发送与使用application/x-www-form-urlencoded
表示或类似的东西没有什么不同。Jim Webber 明确指出,毕竟HTTP 只是一种传输协议,其应用领域是通过 Web 传输文档。客户端和服务器至少应该都支持RFC 7111text/csv
中定义的。此 CSV 文件可以作为处理媒体类型的结果生成,该媒体类型定义了表单元素、将请求发送到的目标元素或属性以及执行配置上传的 HTTP 方法。
有几种媒体类型支持HTML、HAL Forms、halform、ion或Hydra等表单。不过,我目前不知道一种可以自动将输入数据text/csv
直接编码为的媒体类型,因此可能需要在IANA 的媒体类型注册表中定义和注册。
我猜完整参数集的上传和下载应该不是问题。如前所述,目标 URI 不相关,因为客户端只会使用 URI 来检索要处理的新内容。按营业日期过滤也应该不难。然而,这里服务器应该为客户端提供客户端可以选择的所有可能性。近年来,GraphQL 和 RestQL 不断发展,它们引入了一种类似 SQL 的语言,可以针对某个端点来获得过滤的响应。然而,在真正的 REST 意义上,这违反了 REST 背后的理念,因为 a) GraphQL 即仅使用单个端点,这会以某种方式阻止缓存的最佳使用 b) 需要了解可用字段,这可能会导致引入客户端耦合到资源的基本数据模型。
激活或停用某些配置参数只需触发提供此功能的超媒体控件即可。在 HTML 表单中,这可能是一个简单的复选框或列表中的多行选择或类似的。根据表单和它定义的方法,它可能会通过 发送整个配置,PUT
或者对所做的更改很聪明,并且只通过PATCH
. 后者基本上需要计算对更新表示的更改表示,并为服务器提供所需的步骤以将当前表示转换为所需的表示。根据PATH 规范,这必须在事务中完成,以便应用所有步骤或不应用任何步骤。
HTTP 允许并鼓励服务器在应用更改之前预先验证收到的请求。对于PUT,规格说明:
源服务器应该验证 PUT 表示是否与服务器对目标资源的任何约束一致,这些约束不能或不会被 PUT 更改。当源服务器使用与 URI 相关的内部配置信息来设置 GET 响应中表示元数据的值时,这一点尤其重要。当 PUT 表示与目标资源不一致时,源服务器应该通过转换表示或更改资源配置使它们保持一致,或者以包含足够信息的适当错误消息进行响应,以解释表示不合适的原因。建议使用 409(冲突)或 415(不支持的媒体类型)状态代码,后者特定于对 Content-Type 值的约束。
例如,如果目标资源配置为始终具有“text/html”的 Content-Type 并且被 PUT 的表示具有“image/jpeg”的 Content-Type,则源服务器应该执行以下操作之一:
一种。重新配置目标资源以反映新的媒体类型;
湾。将 PUT 表示转换为与资源一致的格式,然后将其保存为新的资源状态;或者,
C。使用 415(不支持的媒体类型)响应拒绝请求,指示目标资源仅限于“text/html”,可能包括指向不同资源的链接,该链接将成为新表示的合适目标。
HTTP 没有准确定义 PUT 方法如何影响源服务器的状态,超出了用户代理请求的意图和源服务器响应的语义所能表达的范围。...
总结这篇文章,您应该使用现有的媒体类型,它允许您向客户端介绍所需或支持的输入参数、将请求发送到的目标位置、要使用的操作以及媒体类型请求必须格式化,或者定义您自己在 IANA 注册的请求。如果要将输入转换为后者可能是必要的text/csv
然后将 CSV 表示上传到服务器。验证应在更改应用于资源之前进行。实际的 URI 不应该与客户端相关,只是用于确定将请求发送到哪里,因此可以由您(服务实现者)自由选择。通过遵循这些步骤,您几乎可以获得随时更改服务器端的自由,并且如果客户端支持使用的媒体类型,则客户端不会因此而中断。