如何避免大型 JSF 视图的部分 http 响应刷新?

How can I avoid a partial http response flush of large JSF views?

今天,我花了几个小时在我们的 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 来生成一定数量的字符串,并在 2000ms 之后的渲染中添加了一些 人工延迟 3 列中的每一列。

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 作为服务器。应用程序本身非常复杂。

我们在 web.xml 中对 Facelets buffer-size 的显式定义解决了这个问题。

<!-- 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 定义了浏览器开始呈现响应的那一刻。在我们的例子中,菜单已经可以渲染并且比预期更早显示。