我正在尝试理解REST。在REST下,GET不得在服务器上触发事务性事务(这是每个人都同意的定义,它是REST的基础)。
所以想象你有一个网站喜欢 stackoverflow.com(我说喜欢所以如果我得到SO的基本细节错误它不会改变任何东西到我的问题),每次有人读一个问题,使用GET,还有一些显示“这个问题已被阅读256次”。
现在有人读了那个问题。计数器现在是257.GET 是事务性的,因为视图的数量增加了,现在又增加了。 “视图数量”在数据库中递增,没有争论(例如,在SO上总是显示任何问题的查看时间。)
那么,REST GET是否与任何类“数量的视图”类似于网站中的功能基本上不兼容?
如果SO主页要么停止显示使用GET访问的纯HTML链接,要么停止显示“此问题已被查看x次”,那么它应该是“RESTFUL”吗?
因为增加DB中的计数器是事务性的,因此“不安全”?
编辑只是为了让人们谷歌搜索这个可以得到一些指示:
来自http://www.xfront.com/REST-Web-Services.html:
4。通过HTTP GET可访问的所有资源都应该是无副作用的。也就是说,请求应该只返回资源的表示。调用资源不应导致修改资源。
现在对我来说,如果表示包含“视图数量”,它就是资源的一部分[并且在SO中“问题的数量”是一个非常重要的信息]并且访问它肯定会修改资源。
这与一个真正的RESTFUL HTTP GET形成鲜明对比,就像你可以在Amazon S3资源上做的那样,你的GET保证不会修改你得到的资源。
但是我仍然很困惑。
答案 0 :(得分:7)
IMO避免GET请求中的统计信息更新,因为“有人这样说”是关于ReST的教条。做什么是务实的。如果这涉及在响应GET请求时更新计数器,那就这样吧。
进一步详细说明,真正重要的(以及建议的原因)是,当消费者意图阅读时,消费者访问的资源不会以任何方式更新或更改它。但是,更新其他数据,特别是日志和统计信息等内容不是问题。简而言之,读取资源不应该对正在读取的资源产生副作用。
编辑:要回答您的自我递增计数器的情况,请问自己您应用的上下文是什么。显然,如果您定义一个名为 counterThatIncrementsItselfWhenBeingRead 的资源,那么它可以:
无论您选择应用哪种解决方案,问题都在于预期的行为。 IMO,一个在读取时递增自身的计数器应该在读取时递增自身。我仍然访问一个资源的表示,虽然寿命非常短,我知道在阅读之后会立即更改。对此没什么不可靠的。
答案 1 :(得分:7)
重要的是,从客户的角度来看,GET是安全的(没有副作用),因此客户可以安全地多次调用GET而不考虑可能产生的任何副作用。
服务器的作用是服务器的责任。在视图计数器的情况下,如果服务器认为计数器的更新是副作用,则必须做出决定。通常它不会,因为计数器首先是资源语义的一部分。
但是,服务器可能决定不为某些请求增加计数器,例如爬虫的GET。
Jan
答案 2 :(得分:5)
你在这里混淆了几个问题。对REST接口的单个请求可以触发后端事务。但是,该交易必须在单一请求的范围内开始和结束 REST接口不应该做的是让多个独立请求参与同一个后端“两阶段提交”事务。
第二个问题是GET请求是否可以进行更新。正如Jan在回答中指出的那样,在某些条件下允许GET产生副作用。他说它比我能说的要好得多,所以读了他的答案。
答案 3 :(得分:3)
GET对于请求所标识的资源是唯一安全且幂等的 - 这是客户需要和应该关注的所有内容。
考虑这一点的最简单方法是考虑执行此类计数的任何机制作为中介(即您正在利用分层约束),该机制监视请求/响应并更新一些其他视图计数资源而不是实际的资源本身。
答案 4 :(得分:1)
仅仅因为通过GET访问页面,并不意味着没有办法增加计数器。例如,您可以使用AJAX POST。
我也认为这种“被动”交易可能会被安全地忽略。访问URL和删除某个对象,访问URL并增加访问计数器之间存在很大差异。我很想知道关于这个问题的其他观点。
编辑我认为HåvardS和我基本上是一致的,触发计数器的GET在技术上可能不是REST,但不值得担心。
答案 5 :(得分:1)
POST用于发送客户端提供给服务器的信息。这不会发生在这里,所以POST是不必要的。
为了维持HTTP交互的无状态(我认为这是REST的目的),GET不必导致任何状态改变;但需要的是它不会从客户端隐藏状态;即,任何对HTTP交互具有未来后果的状态都需要编码到URL空间中,以便客户端可以使用它来处理将来的请求。
该计数器是该州的一部分,如果其价值将影响未来的互动 - 例如,如果在每百万增量之后,“请预订一辆巴士旅游,我们将尝试向您出售您在奥兰多的房地产物业”子系统踢REST基本上说在这种情况下,它应该是URL空间的一部分,因此状态可以作为寻址的一部分显式维护 - 例如,您可以生成一个GET到一个字符串的URL?counter =附加$ cnt(使用$ cnt计数器的值)。
如果没有,它只是视图的一部分 - 客户端没有理由将它或基于它的任何其他信息反馈给服务器,因此不需要它存在于服务器中一个URL(或其他任何地方)。您显示并丢弃它。
答案 6 :(得分:0)
您需要注意的一点是:GET请求可以由机器人触发,例如:搜索引擎。如果您不允许,这些会使您的统计信息出现偏差。
答案 7 :(得分:0)
还有一个想法:
我认为“读取计数”不得递增。想想不代表“读”的各种机器人/爬虫/缓存应用程序。 相反,可能有某种方式触发真正的读取(由客户端)。
/ question / 2363294 - >获取返回问题,但不递增计数器 / question / 2363294 / readCount - >获取返回当前读取计数 / question / 2363294 / readCount - >发布更新读取计数
然后我的好客户端应用程序只是在我真正看了一下就发布了这个。而不是在下载时,例如,因为预取...
答案 8 :(得分:0)
我认为问题更加微妙:当很容易指出读计数器只是统计信息时,开发人员可以根据其他方面决定如何更新它(我应该考虑机器人/爬虫阅读?)在我看来,还有其他情况非常危险。这是一个
GET /users/me/notifications
[{
"id" : 2,
"timestamp" : 0000000001,
"title" : "you win a BMW car!"
"status" : NOT_READ
},
{
"id" : 1,
"timestamp" : 0000000000,
"title" : "Welcome to phishingbanners.com!"
"status" : READ
}]
现在,用户调用此API来获取他/她的通知。完全合理的假设是,一旦调用了API,所有未读的通知就会变为已读。因此GET可能会有副作用,或者我们需要像这样的API
PATCH /users/me/notifications
[{
"id" : 2,
"status" : "READ"
}]
使用这种方法,通知状态更新完全取决于客户端,理论上它可以使用端点将READ通知设置为NOT_READ或忘记将其设置为已读,同时更新通知列表所需的舍入提示数增加了一倍
那么,最实用的方法真的是“无副作用的GET”吗?我们应该容忍即使GET旨在观察状态而不是对其进行突变,同一GET仍可以修改某些资源的状态吗?