说,您提交的表单会影响您的数据库(添加记录/删除/更新它们),这就是您的请求的样子:
POST / application / action = update
现在,您已完成更新,因此您希望将用户带到主页。
Response.sendRedirect / application / action = home
这非常好用。在POST之后向用户发送重定向,因此即使用户尝试通过按F5刷新页面,您也很好。但是,如果您这样做,这将无效:
调用RequestDispatcher.forward(/应用/动作=家)
鉴于在完成更新后您必须显示不同类型的错误/成功消息,您很可能在POST后执行转发。在这种情况下,您如何避免更新操作发生两次?
我觉得很有趣的是,许多安全网站(银行)/支付网关倾向于通过在屏幕上放置文字来通知用户,例如“请不要按回/刷新按钮”。
有没有更好的方法来处理这个?除了要求用户不要按这些按钮?当我上次检查时,有一个叫做“垂直响应缓存”的东西。一个过滤器,用于在会话中标识您的请求的唯一性,并在请求重复时尝试发送缓存的响应。有没有更简单的方法来解决这个经典问题?
以下是我正在讨论的垂直响应缓存解决方案的链接:http://www.fingo.info/en/articles/_1.html。我,但是,不确定这是否真的有效。
答案 0 :(得分:12)
是的,我相信你应该在POST后重定向,但API请求除外。如果不这样做,您不仅要担心在用户使用后退按钮时获取重复的POST,而且当用户尝试使用后退按钮时,浏览器也会给用户提供烦人的对话框。
Response.sendRedirect在实践中起作用,但从技术上讲,这是为此目的发送错误的HTTP响应代码。 sendRedirect发送一个302,但是用于将POST转换为GET的正确代码是303.(但是,如果他们为了响应POST而将302视为303,那么)
通常,您希望重定向将用户发送到任何视图以显示其更改的效果。例如,如果他们编辑窗口小部件,则应将其重定向到该窗口小部件的视图。如果他们删除了一个小部件,他们应该被重定向到小部件存在时可能出现的视图(可能是小部件列表)。
有时候,有一个状态消息可以进一步推动行动发生的事实。执行此操作的一种简单方法是为视图创建一个公共参数,该参数在设置时将显示操作已完成的消息。例如:
/widget?id=12345&msg=Widget+modified.
这里“msg”参数包含消息“Widget modified”。这种方法的一个缺点是,恶意网站可能会给您的用户带来令人困惑/误导性的消息。例如:
/account?msg=Foo+Corp.+hates+you.
如果您真的对此感到担心,可以将邮件的过期签名作为附加参数包含在内。如果签名无效或已过期,则只需显示消息。
答案 1 :(得分:2)
解决POST到GET重定向后向用户显示状态消息问题的最佳解决方案是使用用户会话。
如何强>
将属性添加到用户会话,其值为要显示的消息集。例如。
userSession.put("success_messages", new HashSet<String>(){"Success", "Check your account balance"});
userSession.put("warning_messages", new HashSet<String>(){"Your account balance is low. Recharge immediately"});
并有一个过滤器,用于扫描用户会话中的这些特定属性并输出消息。读取一次后,过滤器应删除属性,因为状态消息通常只显示一次。
答案 2 :(得分:1)
有人认为我已经拥有了一个唯一的ID(可能是一个随机字符串)作为POST提交形式的隐藏表单字段。 ID字符串可以作为“事务ID”放入数据库中。现在,当您更新数据库时,首先检查是否存在具有提交的事务ID的现有记录,如果是,则假设它是重复的并且不更改数据库。
当然,正如我所说,这只是一个想法。我不知道在实践中实际使用了哪些方法。 (我怀疑很多不太关键的网站只是忽略了这个问题,并希望他们的用户能够聪明......如果我看过一个就失去主张; - )
EDIT :正如评论中所指出的,在数据库中存储事务ID可能会占用大量空间,但如果这是一个问题,您可以保留所有事务的内存缓存在最后5分钟/ 1小时/ 1天/无论如何处理的ID。除非你遇到一个坚定的黑客,否则这应该有效......
答案 3 :(得分:1)
我觉得很有趣的是,许多安全网站(银行)/支付网关倾向于通过在屏幕上放置文字来通知用户,例如“请不要按回/刷新按钮”。
有些人发现更好地“禁用此关键页面上的所有Back,Refresh事件”; 我不确定这是好还是不好。
但您解决的解决方案“垂直响应缓存”听起来不错
答案 4 :(得分:1)
它有点不明显但是:
因此,当客户端浏览器完成重定向,获取新页面的图像等时...结果正在等待用户。
另一种方法是让用户痛苦地意识到数据库需要多长时间。
安全更新(2011年1月24日):
密钥易受攻击,因为它是对客户端响应的一部分,所以
此方法要求任何黑客都知道会话ID和随机密钥。
这种方法可能看起来有些过分,但重定向强化机制可用于密码重置等情况。
答案 5 :(得分:0)
如果您正在使用java服务器端脚本并使用struts 2,那么请参考此链接,该链接讨论使用令牌。
http://www.xinotes.org/notes/note/369/
当请求与令牌第一次一起提交时,应该生成令牌并保存在初始页面呈现的会话中,在struts动作中运行带有线程名称作为令牌ID的线程并运行逻辑客户端请求,当客户端再次提交相同的请求时,检查线程是否仍在运行(thread.getcurrentthread()。中断)如果仍在运行,则发送客户端重定向503。
请查看struts 2code的ExecuteAndWaitInterceptor,这个结合token的逻辑将有助于快速点击