如何在响应呈现之前处理多个提交?

Posted

技术标签:

【中文标题】如何在响应呈现之前处理多个提交?【英文标题】:How to handle multiple submits before response is rendered? 【发布时间】:2012-04-22 16:20:37 【问题描述】:

根据测试报告,如果响应呈现速度不够快,有时可能会多次按下按钮,从而导致多次调用后端代码,这是我们不希望的。

应用程序是在 Glassfish 3.1.1 中使用 JSF 2.0 的 Java EE 6 Web Profile。

我想知道应该如何正确处理这个问题,并想到了几个场景:

在呈现响应时,提交应禁用所有使用 javascript 的按钮。 Session 范围内的一个标志表明它已经处于活动状态,因此敏感代码将被跳过并继续重新呈现上一次提交的响应。 延迟处理直到前一个请求完成的同步块。那么应该检测到已经被处理并跳过了。 使用转换等“新”作用域之一来处理检测?

我的直觉是,最好的方法是让敏感代码块原子化,但问题在于呈现正确的响应。

我应该如何处理这个问题?

【问题讨论】:

你尝试过类似 jQuery blockui 的东西吗?顺便说一句,同步块在集群上不起作用。 还没有尝试过。这是在“好吧,我该怎么做?”阶段。 【参考方案1】:

在呈现响应时,提交应该禁用所有使用 javascript 的按钮。

这是最容易以通用方式实现的。如果您碰巧只使用<f:ajax>,则可以使用jsf.ajax.addOnEvent() 以通用方式执行该工作。另一种 JavaScript 方法是创建一种“正在加载”的覆盖层,它会阻止 UI,这样最终用户将无法再与底层页面进行交互。这基本上是一个绝对定位的隐藏<div>,它通过一些opacity(透明度)跨越整个视口。您可以在提交时显示它并在渲染时隐藏它。这种技术的关键字是"modal dialog"。面向 UI 的 JSF 组件库中至少有这样一个组件。例如。 PrimeFaces 在<p:ajaxStatus> 内带有<p:dialog modal="true">,或<p:blockUI>

唯一的缺点是,如果客户端禁用了 JS 或不使用它,它将无法工作,因此不会阻止 HTTP 客户端重复提交。


Session 范围内的一个标志表明它已经处于活动状态,因此敏感代码将被跳过并继续重新呈现上一次提交的响应。

这更多地被称为"synchronizer token pattern",并且曾经被spec issue 559 请求过JSF,目前它在针对2.2 的票证上,但似乎没有任何活动。检测和阻塞部分在技术上很容易实现,但是如果您希望最终用户最终检索到初始请求生成的响应,则同步响应处理部分就不容易实现。异步响应处理很简单:只需不指定任何要更新的组件,即清空 PartialViewContext#getRenderIds() 返回的集合。毕竟这比使用 JS 禁用按钮或阻塞 UI 更健壮。

据我所知,Seam 2 是唯一为此提供可重用 JSF 组件的人,<s:token>。然而,我必须承认,对于一个新的OmniFaces 组件来说,这是一个有趣的想法。也许我会亲自去看看。


延迟处理直到前一个请求完成的同步块。那么应该检测到已经被处理过,跳过了。

一般来说这并不容易实现,这需要更改所有操作方法以检查工作是否已经完成。如果 webapp 在多个服务器上运行,它也将不起作用。同步器令牌更容易,因为它会在调用操作方法之前执行。同步器令牌也更便宜,因为您不会在队列中出现多个请求,这只会消耗线程/资源。


使用转换之类的“新”作用域之一来处理检测?

这个问题不能通过使用托管 bean 范围来解决。托管 bean 作用域有不同的用途:bean 实例的生命周期。

【讨论】:

除了“同步块”之外,您还可以查看此过滤器 - onjava.com/onjava/2004/03/24/examples/RequestControlFilter.java 感谢您提供非常丰富的答案。您还有其他我自己没想到的建议吗? 不客气。不,除了使用 JS 禁用/阻止用户交互或使用同步器令牌模式之外,没有其他方法。 FWIW,我已经为 OmniFaces 看过它,很容易让它在同步请求上工作,但在 ajax 请求上却失败了。另见code.google.com/p/omnifaces/issues/detail?id=76的第 3 条评论【参考方案2】:

正如 Adrian 所说,我也会使用 BlockUI。 Primefaces 有一个BlockUI component。当您通过 ajax 提交表单时,您还可以在请求期间使用覆盖。有关示例,请参阅 Primefaces 的 Ajax Status。

【讨论】:

以上是关于如何在响应呈现之前处理多个提交?的主要内容,如果未能解决你的问题,请参考以下文章

[BotFramework]:如何在瀑布对话框中捕获/提取通过 C# 网络聊天机器人中呈现的自适应卡片提交的值?

如何在没有单独的单击事件处理程序的情况下处理多个表单提交 [关闭]

如何在休眠中处理多个会话事务提交和回滚?

多个异步调用,如何以有意义的方式处理响应

如何使用 go 处理多个 xml API 响应结果?

如何使用 Angular JS 处理表单中的多个提交按钮?