RESTful 幂等性

2024-02-29

我正在利用 ROA(面向资源的架构)设计一个 RESTful Web 服务。

我正在尝试找出一种有效的方法来保证 PUT 请求的幂等性,在服务器指定资源键的情况下创建新资源。

根据我的理解,传统的方法是创建一种事务资源,例如/CREATE_PERSON。创建新人员资源的客户端-服务器交互分为两部分:

第 1 步:获取用于创建新 PERSON 资源的唯一事务 ID:::

**Client request:**
POST /CREATE_PERSON

**Server response:**
200 OK
transaction-id:"as8yfasiob"

步骤 2:在请求中创建新的人员资源,并使用事务 id::: 保证其唯一性

**Client request**
PUT /CREATE_PERSON/{transaction_id}
first_name="Big bubba"

**Server response**
201 Created             // (If the request is a duplicate, it would send this
PersonKey="398u4nsdf"   // same response without creating a new resource.  It
                        // would perhaps send an error response if the was used
                        // on a transaction id non-duplicate request, but I have
                        // control over the client, so I can guarantee that this
                        // won't happen)

我发现这种方法的问题是,它需要向服务器发送两个请求才能执行创建新人员资源的单个操作。这会产生性能问题,增加用户等待客户端完成其请求的机会。

我一直在尝试讨论消除第一步的想法,例如在每个请求中预先发送交易 ID,但我的大多数想法都有其他问题或涉及牺牲应用程序的无状态性。

有没有办法做到这一点?

编辑::::::

我们最终采用的解决方案是让客户端获取 UUID 并将其与请求一起发送。 UUID 是一个非常大的数字,占用 16 个字节(2^128)的空间。与具有编程思维的人的直觉想法相反,随机生成 UUID 并假设它是唯一值是公认的做法。这是因为可能值的数量如此之大,以至于随机生成两个相同数字的几率很低,几乎是不可能的。

需要注意的是,我们让客户端从服务器请求 UUID(GET uuid/)。这是因为我们无法保证客户端运行的环境。如果存在诸如在客户端上播种随机数生成器之类的问题,那么很可能会发生 UUID 冲突。


您在创建操作中使用了错误的 HTTP 动词。RFC 2616 https://www.rfc-editor.org/rfc/rfc2616指定操作的语义POST and PUT.

第 9.5 段:

POST方法用于请求 源服务器接受 请求中包含的实体为 资源的新下属 由请求行中的请求 URI 标识

第 9.6 段

PUT方法要求 封闭的实体存储在 提供的请求 URI。

该行为有一些微妙的细节,例如PUT可用于在指定 URL 处创建新资源(如果尚不存在)。然而,POST永远不应该将新实体放在请求 URL 处并且PUT应始终将任何新实体放在请求 URL 处。与请求 URL 的关系定义POST as CREATE and PUT as UPDATE.

根据该语义,如果您想使用PUT要创建一个新人,应该创建于/CREATE_PERSON/{transaction_id}。换句话说,您的第一个请求返回的交易 ID 应该是稍后用于获取该记录的人员密钥。你不应该做PUT请求的 URL 不会是该记录的最终位置。

不过,更好的是,您可以通过使用POST to /CREATE_PERSON。这允许您通过单个请求来创建新的人员记录,并在响应中获取新的 ID(也应在 HTTP 中引用)Location标题也是如此)。

同时,REST 准则指定动词不应成为资源 URL 的一部分。因此,创建新人员的 URL 应该与获取所有人员列表的位置相同 -/PERSONS(我更喜欢复数形式:-))。

因此,您的 REST API 变为:

  • 让所有人 -GET /PERSONS
  • 获得单身人士 -GET /PERSONS/{id}
  • 创建新人 -POST /PERSONS主体包含新记录的数据
  • 更新现有人员或创建具有已知 ID 的新人员 -PUT /PERSONS/{id}主体包含更新记录的数据。
  • 删除现有人员 -DELETE /PERSONS/{id}

注意:我个人不喜欢使用 PUT 来创建记录,原因有两个,除非我需要创建一个与来自不同数据集的现有记录具有相同 id 的子记录(也称为“穷人的外键”: -))。

Update:你是对的POST不是幂等的,这是根据 HTTP 规范的。POST will always返回一个新资源。在上面的示例中,新资源将是事务上下文。

然而,我的观点是你想要PUT用于创建新资源(人员记录),并且根据 HTTP 规范,该新资源本身应位于 URL 处。特别是,您的方法的问题在于您使用的 URLPUT是由 POST 创建的事务上下文的表示,而不是新资源本身的表示。换句话说,人员记录是更新交易记录的副作用,而不是更新的直接结果(更新的交易记录)。

当然,通过这种方法PUT请求将是幂等的,因为一旦创建了人员记录并且事务“最终确定”,后续的PUT请求不会执行任何操作。但现在你有一个不同的问题 - 要实际更新该人的记录,你需要制作一个PUT请求不同的 URL - 代表人员记录的 URL,而不是创建该记录的事务。因此,现在您有两个单独的 URL,您的 API 客户端必须知道它们并发出请求才能操作同一资源。

或者,您也可以在事务记录中复制最后一个资源状态的完整表示,并让人员记录更新也通过事务 URL 进行更新。但此时交易URLis出于意图和目的,个人记录,这意味着它是由POST请求放在第一位。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RESTful 幂等性 的相关文章

  • 将文件和关联数据发布到 RESTful Web 服务(最好以 JSON 形式)

    在一个应用程序中 我正在开发 RESTful API 我们希望客户端以 JSON 形式发送数据 该应用程序的一部分要求客户端上传文件 通常是图像 以及有关图像的信息 我很难在单个请求中追踪这种情况是如何发生的 是否可以将文件数据 Base6
  • 使用 PayPal REST API,如何取消付款?

    使用 PayPal REST API 在客户点击 取消订单并返回网站 链接后 我似乎无法弄清楚如何取消付款 也许在生产模式下 PayPal 会自动取消这些付款 但在沙盒模式下它们似乎仍处于 已创建 状态 这一观察结果使我相信 我需要在返回网
  • 使用 Ruby Curb 传递 GET 参数

    我正在尝试使用 Curb curb rubyforge org 调用需要在 get 请求中提供参数的 RESTful API 我想获取一个像这样的URLhttp foo com bar xml bla blablabla 我希望能够做类似的
  • 寻找在 Ruby on Rails 中构建安全 REST API 的建议

    我正开始为我正在从事的项目构建 REST API 这促使我对使用 RoR 构建 API 的最佳方法进行了一些研究 我很快发现 默认情况下 模型是向世界开放的 只需在 URL 末尾添加 xml 并传递适当的参数即可通过 URL 进行调用 那么
  • 为什么我无法使用 HttpUrlConnection 上传第一个文件块?

    在我的项目中 我应该从一台服务器逐块下载文件 并将每个块立即上传到另一台服务器 我有一个应该下载的文件的 URL 我们就这样称呼它吧downloadUrl 因此 这就是我逐块下载文件的方式 val chunkSize 1024 1024 B
  • 如何从 Android 应用程序调用 REST API? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我是 android 新手 也是编程新手 如何从 Android 应用程序调用 REST api GET POST 请求 请给我推荐一
  • 在自定义控制器中接受 Spring Data REST URI

    我有一个 Spring Data Rest webmvc 应用程序 我想为其添加一些自定义功能以进行批量操作 我创建了一个控制器 并将其混合到 uri 命名空间中 但我希望它能够像自定义一样接受 URI search查询确实如此 而不仅仅是
  • 在 Spring 应用程序中拥有 RestController 和 Controller 的最佳实践

    我不是问是不是possible 我知道是这样 但我想知道在我的应用程序中拥有前端的同时提供休息服务的最佳方式是什么 我正在开发一个 Spring Boot 应用程序 我目前有一个调用 jsp 页面的控制器 以及一个separate休息控制器
  • Spring Boot 自定义 ErrorAttributes http 状态未设置为响应

    继Spring Boot之后文档 http docs spring io spring boot docs current reference htmlsingle boot features error handling我定义了自己的 E
  • Java HttpURLConnection:内容长度计算

    我目前正在为 bitbucket issues RESTful API 开发一个库 我取得了很大的进步 现在我要解决这个部分更新问题 http confluence atlassian com display BBDEV Issues Is
  • 当 REST 中的资源不支持操作时,HTTP 状态代码 404 或 501

    我有一个 REST 服务 根据正在查看的资源类型 我有某些可用的操作 So Resource1支持Operation1 and Operation2 eg Resource1 Operation1 Resource1 Operation2
  • 如何访问 NFL 的 API?

    我一直在尝试访问或设法访问 NFL com 的数据 但尚未找到 这些网站上有公开文档 https api nfl com docs identity oauth2 index html 但这些文档不会告诉您如何获取客户端 ID 或客户端密钥
  • 在应用程序中注册API

    通过 django rest framework 我正在使用DefaultRouter 我想为多个应用程序提供 API 所以我的问题是我能否以 django 方式执行此操作 并将我的路由器注册放入每个应用程序 URLconf 中 并让它们显
  • 使用 Spring RestTemplate 时忽略 SSL 证书验证

    我正在使用 Spring RestTemplate 发出 HTTPS 请求 并且我想忽略 SSL 证书 这是我创建restTemplate请求的代码 TrustStrategy acceptingTrustStrategy X509Cert
  • 如何进行 REST 式更新?

    如果我有一个对象 请说Employee 我想提供两种不同的更新方式 更新绩效评级或更新联系信息 构建 API 的 REST 式方式是什么 我认为正确的方法是 POST 我担心的是 对于用户来说 首先获取对象的两个部分 绩效评级和联系信息 仅
  • 从 Office 365 日历获取所有事件

    我需要获取 Office 365 日历中的所有事件 当前 GET 请求 https graph microsoft com v1 0 users https graph microsoft com v1 0 users userPrinci
  • iPhone 应用程序中的异步、同步、线程

    我正处于一个应用程序的设计阶段 该应用程序将利用 REST Web 服务 并且在使用异步 同步和线程方面遇到了困境 这是场景 假设您有三个选项可供深入研究 每个选项都有自己的基于 REST 的资源 我可以使用同步请求延迟加载每个请求 但这会
  • REST Web 服务 WSDL? [复制]

    这个问题在这里已经有答案了 我正在实现一个 Web 服务 并且已经实现了 REST 和 SOAP 版本 看看哪个版本适合我的需求 我决定选择 REST 因为它很简单 而且我可能会开发一个 iPhone 应用程序来使用它 我的问题很简单 是否
  • 在 Angular 中让多个调用等待同一个 Promise

    我在一个页面上有多个使用相同服务的控制器 为了举例 我们将服务称为 USER 第一次调用 USER getUser 时 它会发出 http 请求来获取有关用户的数据 调用完成后 它将数据存储在 USER data 中 如果再次调用 USER
  • 将 List 转换为 JSON

    Hi guys 有人可以帮助我 如何将我的 HQL 查询结果转换为带有对象列表的 JSON 并通过休息服务获取它 这是我的服务方法 它返回查询结果列表 Override public List

随机推荐