我正在实现一个访问数据库的RESTful Web服务。对数据库中的实体进行版本控制以检测多个更新。例如,如果当前值为{"name":"Bill", "comment":"tinker", "version":3}
,则如果一个用户PUT {"name":"Bill", "comment":"tailor", "version":3}
,则请求将成功(200 OK),新值将为{"name":"Bill", "comment":"tailor", "version":4}
。如果请求的第二个用户PUT {"name":"Bill", "comment":"sailor", "version":3"}
将失败(409 Conflict),因为版本号不匹配。
存在非RESTful接口,因此无法更改数据库的设计。 RESTful接口调用现有接口来处理检查版本的详细信息。
RESTful Web服务中的经验法则是尽可能遵循HTTP的详细信息。在这种情况下,在请求中使用条件头并且如果版本不匹配则返回412 Precondition Failed会更好吗?相应的标题似乎是If-Match。此标头采用ETag(实体标记),它可以是资源当前状态表示的散列。
如果我这样做的话,ETags会出于外表的缘故,因为版本仍然是我正在测试的真实内容。
我有什么理由这样做,除了“让它更加RESTful”,无论这意味着什么?
答案 0 :(得分:19)
如果你正在使用HTTP,那么适当的做法就是遵循HTTP规范,原因只是让了解规范的人正确运行。
只有在前提条件(例如If-Match)导致版本匹配失败时才应使用412,而如果实体会导致冲突,则应使用 409 (HTTP规范本身在definition of 409中暗示了这种行为。)
因此,不发送ETag的客户端将不会期望412.相反,发送ETag的客户端将不会理解它是导致409的ETag。
我会坚持一种方式。你说“数据库模式不能改变”,但这并不能阻止你(在HTTP服务器层中)从数据库表示中提取版本并将其放入ETag中,然后在途中,获取If-Match标头并将其放回版本字段中。
但是不禁止在实体主体中完成它。它只需要您解释概念及其工作原理,而使用ETag解决方案,您可以将人们指向HTTP规范。
编辑:版本标志不必是当前资源的哈希值;一个版本是完全可以接受的ETag: "3"
是完全有效的ETag。