将复杂对象传递给 REST 服务的 delete 方法
Pass complex object to delete method of REST Service
我有管理资源 EASYPAY
的 REST 服务。此时此服务公开了 3 种不同的方法:
- 获取 EasyPay 请求(
GET
);
- 插入 Easypay 请求(
POST
);
- 更新 Easypay 请求(
PUT
)。
当我插入或更新请求时,我还必须在我的数据库的 trace
table 上插入一行。
现在我必须删除一个 Easypay 请求,我还必须在跟踪 table 上添加一行。
我想使用 DELETE
HTTP 动词,但我看到使用 delete 我不能传递复杂对象,而只能传递要删除的请求的 ID。
我不能使用 PUT
HTTP 动词,因为我已经使用过它,而且无论如何它在概念上都不正确......
我不想做更多从客户端到服务器的调用(一个用于删除请求,另一个用于在跟踪 table 中添加一行)。
所以不知道怎么解决。
编辑
我试着解释得更好...我有一个部署在两个不同服务器上的网站。一个用于前端,一个用于后端。后端只为前端公开一些 REST 服务,它无法访问 Internet(只能访问 Intranet)。
访问该网站的客户可以通过称为 XPAY 的系统进行支付,它的工作原理与贝宝非常相似(XPAY 只是另一个虚拟 POS)。
因此,当客户尝试付款时,我会在数据库中保存一些信息 + 我会跟踪付款尝试,然后他会被重定向到 XPAY。在那里,他可以付款。最后 XPAY return 到网站(前端)向我们传达付款结果。
结果在支付的URL中,所以我必须把url中的所有信息都拿去发给后台。
根据结果,我必须更新(如果结果是 ok)或删除(如果结果是 ko)我之前保存的信息,并在轨迹上写一行table。
你有什么建议?
谢谢
实际上有几种方法可以解决您的问题。首先,REST 只是一种架构风格,而不是一种协议。因此 REST 不规定必须如何组成 URI 或传递什么参数。它只需要一个唯一的资源标识符,可能应该是 self-descriptive,这意味着客户端可以根据返回的内容采取进一步的操作(HATEOAS,甚至包括指向自身的链接和适当的内容类型规范)。
删除
因为您想在其他 table 中保留已删除资源的踪迹,您可以在 URI 本身内传递数据,也可以作为查询参数(甚至 JSON 可以按顺序编码作为查询参数传递)或使用自定义 HTTP headers 将(元)信息传递到后端。
发送复杂的 object(无论是 XML 还是 JSON)作为查询参数可能会导致某些问题,尽管某些 HTTP 框架限制了 maximum URI size to roughly 2000 characters.因此,如果调用的 URI 超过此限制,后端可能无法完成请求。
尽管超文本传输协议没有定义 headers certain implementations may raise an error if the request is to large 的最大数量(或大小)。
POST
您当然也可以向后端发送一个新的临时资源,该资源可用于删除待处理的付款请求并向跟踪添加一个新条目table。
根据 spec:
The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.
这使得 POST
请求可用于在服务器端触发某些处理的短期临时资源。如果您想设计一些 queue-like 或侦听器系统,您可以在其中放置要执行的操作到系统中,这将很有用。由于 POST
请求可能包含 body,因此您可以在 POST
请求的 body 内发送 POS 响应。然后可以使用此操作请求删除待处理的 POS 请求并向跟踪添加新条目 table.
PATCH
补丁是客户端可以指示服务器将一个或多个资源从状态 1 转换为状态 2 的一种方式。因此,客户端负责分解服务器必须采取的将资源转换为状态的必要操作当服务器尝试执行它们时它们的期望状态。客户端总是在已知状态(它在之前某个时间收集的)上工作。这允许客户端将当前状态修改为所需状态,因此知道转换所需的步骤。根据其原子要求,要么所有指令都成功,要么其中 none 个指令成功。
您的场景的 JSON Patch 可能如下所示:
PATCH /path/to/resource HTTP/1.1
Host: backend.server.org
Content-lengt: 137
Content-Type: application/json-patch+json
If-Match: "abc123"
[
{ "op": "remove", "path": "/easyPayRequest/12345" }
{ "op": "add", "path": "/trace/12345", "value": [ "answer": "POSAnswerHere" ] }
]
其中 12345
是实际 easypay 请求的 ID,POSAnswerHere
应替换为 POS 服务的实际响应或后端进一步希望作为跟踪写入的内容。
示例中的If-Match
header只是保证补丁请求在最新的已知状态上执行。如果同时有一个进一步的进程改变了状态(它也会生成一个新的 If-Match 值),请求将失败并显示 412 Precondition Failed
失败。
讨论
虽然 DELETE
最初可能是首选,但在我看来,它并不是您所处情况的最佳解决方案,因为此请求并不是真正的幂等。实际的 POS 实体删除是幂等的,但跟踪的添加不是因为同一请求的多次发送将为每个请求添加一个条目 (-> side-effect)。然而,这在某种程度上与 DELETE
操作的幂等性要求相矛盾。
另一方面,POST
是一个 all-purpose 操作,不保证幂等性(因为 PATCH
也不保证)。虽然它主要用于在服务器端创建新资源,但只有服务器(或 server-application 的创建者)知道它实际对请求做了什么(尽管这可能扩展到所有操作)。由于没有事务限制,添加跟踪可能会成功,而删除挂起的请求实体可能会失败,反之亦然。虽然这可能由 dev-team 处理,但实际操作并未对此问题提供任何保证。如果服务器不在您自己手中,因此无法轻松修改或检查,这可能是一个主要问题。
PATCH
请求仍然在 RFC 中,因此可能包含比 POST
请求更多的语义。它还指定了针对每个请求明确修改多个资源的能力,并坚持原子性,这也需要 transaction-like 处理。 JSON 补丁非常直观,传达了更多语义,然后只需将 POS 响应添加到 POST
实体 body。
因此,在我看来 PATCH
应该优于 POST
或 DELETE
。
我有管理资源 EASYPAY
的 REST 服务。此时此服务公开了 3 种不同的方法:
- 获取 EasyPay 请求(
GET
); - 插入 Easypay 请求(
POST
); - 更新 Easypay 请求(
PUT
)。
当我插入或更新请求时,我还必须在我的数据库的 trace
table 上插入一行。
现在我必须删除一个 Easypay 请求,我还必须在跟踪 table 上添加一行。
我想使用 DELETE
HTTP 动词,但我看到使用 delete 我不能传递复杂对象,而只能传递要删除的请求的 ID。
我不能使用 PUT
HTTP 动词,因为我已经使用过它,而且无论如何它在概念上都不正确......
我不想做更多从客户端到服务器的调用(一个用于删除请求,另一个用于在跟踪 table 中添加一行)。
所以不知道怎么解决。
编辑
我试着解释得更好...我有一个部署在两个不同服务器上的网站。一个用于前端,一个用于后端。后端只为前端公开一些 REST 服务,它无法访问 Internet(只能访问 Intranet)。 访问该网站的客户可以通过称为 XPAY 的系统进行支付,它的工作原理与贝宝非常相似(XPAY 只是另一个虚拟 POS)。 因此,当客户尝试付款时,我会在数据库中保存一些信息 + 我会跟踪付款尝试,然后他会被重定向到 XPAY。在那里,他可以付款。最后 XPAY return 到网站(前端)向我们传达付款结果。 结果在支付的URL中,所以我必须把url中的所有信息都拿去发给后台。 根据结果,我必须更新(如果结果是 ok)或删除(如果结果是 ko)我之前保存的信息,并在轨迹上写一行table。
你有什么建议?
谢谢
实际上有几种方法可以解决您的问题。首先,REST 只是一种架构风格,而不是一种协议。因此 REST 不规定必须如何组成 URI 或传递什么参数。它只需要一个唯一的资源标识符,可能应该是 self-descriptive,这意味着客户端可以根据返回的内容采取进一步的操作(HATEOAS,甚至包括指向自身的链接和适当的内容类型规范)。
删除
因为您想在其他 table 中保留已删除资源的踪迹,您可以在 URI 本身内传递数据,也可以作为查询参数(甚至 JSON 可以按顺序编码作为查询参数传递)或使用自定义 HTTP headers 将(元)信息传递到后端。
发送复杂的 object(无论是 XML 还是 JSON)作为查询参数可能会导致某些问题,尽管某些 HTTP 框架限制了 maximum URI size to roughly 2000 characters.因此,如果调用的 URI 超过此限制,后端可能无法完成请求。
尽管超文本传输协议没有定义 headers certain implementations may raise an error if the request is to large 的最大数量(或大小)。
POST
您当然也可以向后端发送一个新的临时资源,该资源可用于删除待处理的付款请求并向跟踪添加一个新条目table。
根据 spec:
The action performed by the POST method might not result in a resource that can be identified by a URI. In this case, either 200 (OK) or 204 (No Content) is the appropriate response status, depending on whether or not the response includes an entity that describes the result.
这使得 POST
请求可用于在服务器端触发某些处理的短期临时资源。如果您想设计一些 queue-like 或侦听器系统,您可以在其中放置要执行的操作到系统中,这将很有用。由于 POST
请求可能包含 body,因此您可以在 POST
请求的 body 内发送 POS 响应。然后可以使用此操作请求删除待处理的 POS 请求并向跟踪添加新条目 table.
PATCH
补丁是客户端可以指示服务器将一个或多个资源从状态 1 转换为状态 2 的一种方式。因此,客户端负责分解服务器必须采取的将资源转换为状态的必要操作当服务器尝试执行它们时它们的期望状态。客户端总是在已知状态(它在之前某个时间收集的)上工作。这允许客户端将当前状态修改为所需状态,因此知道转换所需的步骤。根据其原子要求,要么所有指令都成功,要么其中 none 个指令成功。
您的场景的 JSON Patch 可能如下所示:
PATCH /path/to/resource HTTP/1.1
Host: backend.server.org
Content-lengt: 137
Content-Type: application/json-patch+json
If-Match: "abc123"
[
{ "op": "remove", "path": "/easyPayRequest/12345" }
{ "op": "add", "path": "/trace/12345", "value": [ "answer": "POSAnswerHere" ] }
]
其中 12345
是实际 easypay 请求的 ID,POSAnswerHere
应替换为 POS 服务的实际响应或后端进一步希望作为跟踪写入的内容。
示例中的If-Match
header只是保证补丁请求在最新的已知状态上执行。如果同时有一个进一步的进程改变了状态(它也会生成一个新的 If-Match 值),请求将失败并显示 412 Precondition Failed
失败。
讨论
虽然 DELETE
最初可能是首选,但在我看来,它并不是您所处情况的最佳解决方案,因为此请求并不是真正的幂等。实际的 POS 实体删除是幂等的,但跟踪的添加不是因为同一请求的多次发送将为每个请求添加一个条目 (-> side-effect)。然而,这在某种程度上与 DELETE
操作的幂等性要求相矛盾。
POST
是一个 all-purpose 操作,不保证幂等性(因为 PATCH
也不保证)。虽然它主要用于在服务器端创建新资源,但只有服务器(或 server-application 的创建者)知道它实际对请求做了什么(尽管这可能扩展到所有操作)。由于没有事务限制,添加跟踪可能会成功,而删除挂起的请求实体可能会失败,反之亦然。虽然这可能由 dev-team 处理,但实际操作并未对此问题提供任何保证。如果服务器不在您自己手中,因此无法轻松修改或检查,这可能是一个主要问题。
PATCH
请求仍然在 RFC 中,因此可能包含比 POST
请求更多的语义。它还指定了针对每个请求明确修改多个资源的能力,并坚持原子性,这也需要 transaction-like 处理。 JSON 补丁非常直观,传达了更多语义,然后只需将 POS 响应添加到 POST
实体 body。
因此,在我看来 PATCH
应该优于 POST
或 DELETE
。