POST后你总是重定向吗?如果是的话,你如何管理它?

时间:2009-07-05 02:32:45

标签: java java-ee form-submit

说,您提交的表单会影响您的数据库(添加记录/删除/更新它们),这就是您的请求的样子:

POST / application / action = update

现在,您已完成更新,因此您希望将用户带到主页。

Response.sendRedirect / application / action = home

这非常好用。在POST之后向用户发送重定向,因此即使用户尝试通过按F5刷新页面,您也很好。但是,如果您这样做,这将无效:

调用RequestDispatcher.forward(/应用/动作=家)

鉴于在完成更新后您必须显示不同类型的错误/成功消息,您很可能在POST后执行转发。在这种情况下,您如何避免更新操作发生两次?

我觉得很有趣的是,许多安全网站(银行)/支付网关倾向于通过在屏幕上放置文字来通知用户,例如“请不要按回/刷新按钮”。

有没有更好的方法来处理这个?除了要求用户不要按这些按钮?当我上次检查时,有一个叫做“垂直响应缓存”的东西。一个过滤器,用于在会话中标识您的请求的唯一性,并在请求重复时尝试发送缓存的响应。有没有更简单的方法来解决这个经典问题?

以下是我正在讨论的垂直响应缓存解决方案的链接:http://www.fingo.info/en/articles/_1.html。我,但是,不确定这是否真的有效。

6 个答案:

答案 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)

它有点不明显但是:

  • 在用户会话中创建一个键控对象。
  • 该值是结果的Request + java Future
  • 立即返回客户端重定向。
  • 在处理客户端重定向时,让工作线程处理产生答案。

因此,当客户端浏览器完成重定向,获取新页面的图像等时...结果正在等待用户。

另一种方法是让用户痛苦地意识到数据库需要多长时间。

安全更新(2011年1月24日):

密钥易受攻击,因为它是对客户端响应的一部分,所以

  1. 生成随机密钥
  2. 使用用户的会话ID作为salt来创建SHA-1
  3. 将随机密钥和SHA-1存储在数据库中,并使用(,)作为主键。 (在RANDOMKEY上没有单独的索引。
  4. 使用RANDOMKEY和SHA-1作为数据库查找。
  5. 不存储会话ID(避免隐私问题,因为能够将多个条目同化为同一用户)
  6. 2-3天后过期结果。 (允许每日批处理作业进行清理,并避免为半持久的用户会话创建问题)
  7. 此方法要求任何黑客都知道会话ID和随机密钥。

    这种方法可能看起来有些过分,但重定向强化机制可用于密码重置等情况。

答案 5 :(得分:0)

如果您正在使用java服务器端脚本并使用struts 2,那么请参考此链接,该链接讨论使用令牌。

http://www.xinotes.org/notes/note/369/

当请求与令牌第一次一起提交时,应该生成令牌并保存在初始页面呈现的会话中,在struts动作中运行带有线程名称作为令牌ID的线程并运行逻辑客户端请求,当客户端再次提交相同的请求时,检查线程是否仍在运行(thread.getcurrentthread()。中断)如果仍在运行,则发送客户端重定向503。

请查看struts 2code的ExecuteAndWaitInterceptor,这个结合token的逻辑将有助于快速点击