每个用户都有一个 gem Collection 。可以通过 REST API 访问这些 gem:
GET /user/<user id>/gem -> get all gems
GET /user/<user id>/gem/<gem id> -> get an existing gem
POST /user/<user id>/gem -> add a new gem
PUT /user/<user id>/gem/<gem id> -> edit an existing gem
DELETE /user/<user id>/gem/<gem id> -> delete an existing gem
我有几个后端进程,它们同时运行并且可以通过 POST
HTTP 方法添加 gem。 (他们还可以编辑 (PUT
) 或删除 (DELETE
) gem ,但这对我的问题并不重要。实际上,它很重要。请继续阅读。)
从高层次的角度来看,他们做了以下事情:
1. GET /user/<current user id>/gem
2. some calculations, based on step 1
3a. if (step 2 decided that a gem should be added)
3b. POST /user/<current user id>/gem
如前所述,这些进程并行运行。通常,两个进程不管理同一用户的 gem,但这种情况可能会发生。
所以我需要一种机制来禁止在步骤 3b
中的 POST
如果同时发生某些事情。我考虑过使用 ETag 和乐观锁定:
1. GET /user/<current user id>/gem and remember the returned ETag
2. some calculations, based on step 1
3a. if (step 2 decided that a gem should be added)
3b. POST /user/<current user id>/gem with header 'If-Match=<ETag from step 1>'
3c. if (server returns 412 - precondition failed)
3d. start again at step 1
我不确定 ETag 是否适用于此。大多数 ETag 的例子都是关于一个单一的资源(例如 /gem/23
),而不是关于资源的集合(例如 /gem
)。也就是说,在步骤 3b
中,我提供了完整的 gem 集合的 ETag,而实际上我提供了要添加的单个 gem。
最佳答案
当然,您的问题听起来非常适合 ETag 的使用。它是一个集合这一事实并不重要;重要的是它是一种具有表示的资源,您可以从中始终如一地生成 ETag。
要考虑的一件事是,集合的表示是否有任何可以更改的内容,而这对您的 API 使用者来说并不重要。例如,假设您以某种随机或不一致的顺序输出集合,但集合在语义上定义为无序。在那种情况下,您可以生成 weak ETag基于集合中的项目集。
关于java - REST - POST 到资源集合和 If-Match header 时的 ETag,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38843625/