【问题标题】:How can I avoid a partial http response flush of large JSF views?如何避免大型 JSF 视图的部分 http 响应刷新?
【发布时间】:2018-03-21 13:47:52
【问题描述】:

今天我花了几个小时在我们的 Web 应用程序中使用 JSF facelets 重现了一个非常奇怪的 UI 行为: 在某些情况下,在服务器端真正完成呈现整个视图之前,UI 已在 Web 浏览器中部分呈现。

最后,这一切都归结为一个包含大量元素的 JSF 视图——在我的例子中是一个子菜单项。似乎有一些阈值会触发响应的部分刷新

这是一个最小化的示例,直观地展示了这种效果:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="de" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
    <style>
        td {
            vertical-align: top;
        }
    </style>
</h:head>
<h:body>

    <h1>EURNEU-10056</h1>

    <table>
        <tr>
            <td>
                <ol>
                    <ui:repeat value="#{bean.strings(10)}" var="str">
                        <li><h:outputText value="#{str}" /></li>
                    </ui:repeat>
                </ol>
                <h:outputText value="#{bean.delay(2000)}" />
            </td>
            <td>
                <ol>
                    <ui:repeat value="#{bean.strings(10)}" var="str">
                        <li><h:outputText value="#{str}" /></li>
                    </ui:repeat>
                </ol>
                <h:outputText value="#{bean.delay(2000)}" />
            </td>
            <td><ol>
                    <ui:repeat value="#{bean.strings(10)}" var="str">
                        <li><h:outputText value="#{str}" /></li>
                    </ui:repeat>
                </ol>
                <h:outputText value="#{bean.delay(2000)}" />
            </td>
        </tr>
    </table>

</h:body>
</html>

该简单视图使用以下 bean 生成一定数量的字符串,并在 3 列中的每一列之后的 2000ms 渲染中添加一些 人为延迟。 p>

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import javax.faces.bean.ManagedBean;

@ManagedBean
public class Bean implements Serializable {

    private static final long serialVersionUID = 1L;

    public List<String> strings(int count) {
        List<String> all = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            all.add(UUID.randomUUID().toString());
        }
        return all;
    }

    public String delay(int delay) {
        try {
            Thread.sleep(delay);
        }
        catch (InterruptedException ex) {
            // NOP;
        }
        return String.format("This string has been delayed for %d ms!", delay);
    }

}

浏览器在处理请求时显示以下阶段:

如果我在生成视图时减少使用的字符串数量,则响应只会在渲染阶段结束时刷新。

我可以做些什么来避免部分渲染?(除了减少元素的数量)

PS:我们使用 JBoss EAP v7.0.9 作为服务器。应用程序本身相当复杂。

【问题讨论】:

  • 这不是什么奇怪的行为。那是缓冲输出。如果您有一个输出信息行的 3 小时运行流程,您希望在流程结束之前获取这些行。如果您的输出为 17MB 或 100MB,该怎么办。谁必须缓冲它才能不做部分输出?
  • 我们用 32kB 的 HTML 代码实现了刷新效果……它与 JSF 视图中的元素数量有关……而不是 HTML 的输出大小。
  • 但原则仍然存在。也许,JSF 控件会执行一些刷新或强制刷新。
  • 当然...但是我可以调整任何设置吗? BufferSize 某处?我仍在寻找导致该效果的相关组件/设置。否则我必须在我们的 UI 中改造菜单。在大多数情况下效果很小……但有些页面需要大约 10 秒才能完成完整渲染阶段,用户看到部分加载的页面会感到很困惑。
  • 10 秒!!!那不是对话速度……在 glassfish 'server-config' - 'HTTP Service' 中,您会找到 32k 缓冲区。或“服务器配置”-“网络配置”-“协议”-“http-listener1”-“HTTP”

标签: jsf render facelets


【解决方案1】:

这让我们在 web.xml 中明确定义 Facelets 缓冲区大小解决了这个问题。

<!-- We raise the buffer size to avoid partial rendering of complex pages. -->
<context-param>
    <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
    <param-value>1024000</param-value>
</context-param>

该设置和生成的 HTML 的结构定义了浏览器开始呈现响应的那一刻。在我们的例子中,菜单已经可以渲染并且比预期的要早得多。

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 2013-08-13
    • 1970-01-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多