我们有一对 REST 应用程序试图通过使用确认 URL 来实现事务的轻量级版本,该确认 URL 指示双方“提交”修改的时间。以下是步骤 - 这些步骤不会立即完成 - 步骤之间可能会暂停以供最终用户批准。
- 应用程序 A 批准并分阶段进行更改,通知应用程序 B 它已准备好进行更改
- 应用程序 B 暂存更改并通知应用程序 A 它已准备好,并提供应用程序 A 在执行提交时将“命中”的确认 URL。
- 应用程序 A “点击”确认 URL,收到后,应用程序 B 提交更改并返回 200。如果应用程序 A 得到 200,他们提交更改,否则每个人都回滚。
问题是关于确认 URL 的正确操作是什么。有两种“合理”的选择——每一种都有缺点:
使用 GET 请求 - 缺陷是数据正在被修改,GET 不应该允许这样做。
使用 PUT 请求 - 这更有意义,因为数据已更改并且它只
应该发生一次。但是 PUT 请求需要
Content-Length 标头,并且由于没有要发送的数据,许多 HTTP
客户端库拒绝设置“Content-Length:0”。因此,它们会产生“损坏的” PUT,并且当您发送没有内容项的 PUT 时,您经常(正确地)收到 411。解决方案是发送单个字符主体 - 它使 PUT 有效但感觉有点恶心。
这是一个狭隘的问题,询问我们是否应该使用带有单个字符主体的 GET 或 PUT 来设计协议。
需要明确的是,并非所有 HTTP 客户端都拒绝发送 Content-Length: 0 标头,但 Java HttpURLConnection 只有在您实际在 PUT 上发送数据时才会发送标头。并不是所有的 HTTP 服务器在收到没有 Content-Length 标头的 PUT 时都会抛出 411,但 Rails(和其他)正确地执行了该规则。我们需要这个协议在所有语言、HTTP 服务器和 HTTP 客户端上工作,所以“用 X 重写它”的答案是没有帮助的。
这是一个 REST 哲学问题,而不是“哪种语言更好”的问题。