用户点了一次按钮,服务器却可能收到两次请求。这不是前端写错了,而是网络本身就不保证"一次点击等于一次请求"。
任何调用较慢服务的网页操作,都要面对一个熟悉的失败场景:服务器其实已经把活干完了,但响应在回到浏览器之前消失了。用户看到没反应,自然会再点一次。
如果后端把这次重试当成一个全新操作,同一个请求就可能消耗两次额度,或者产出两份重复结果。按钮被点了一次,并不能保证只有一个请求抵达服务器。
一个有用的设计模式,是给每一个"意图中的操作"配一个稳定的幂等键(idempotency key)。服务器在开始昂贵计算之前,先把这把键记下来。之后再来一个带同样键的请求,直接返回已有的操作状态,而不是另起一摊。
一种可能的状态模型是这样的:
- reserved(已预留)
- completed(已完成)
- failed(已失败)
预留要绑定到具体用户和具体意图操作上。另外可以给一个独立的操作 ID,让客户端在超时之后还能来问状态。界面据此显示"仍在处理""已完成"或"已失败",而不是靠用户点没点按钮去猜。
真正麻烦的是上游超时。超时不等于服务商什么都没做。在释放预留、或者新建一个上游请求之前,得先确认原来的操作能不能被找到,或者能不能用同一个幂等键安全重试。否则一次超时就会变成两份重复的工作。
这套东西是设计模式,不是对某个具体产品实现的断言。额度规则怎么定,取决于产品对用户的承诺:失败的尝试收不收费、挂起的任务占不占容量、一个操作允许悬而未决多久。这些选择要明确写出来,然后拿并发启动、浏览器重试、上游超时、延迟响应这几种情况去测。
说白了,额度安全的前提是把"操作"当成一个有身份、有状态的东西来管,而不是把每次请求都当成孤立事件。用户点一次,系统就该只认一次。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.