PrimeFaces 6.0 不在客户端缓存图像

PrimeFaces 6.0 does not cache images on the client side

给定其中一列中的 <p:dataTable> 渲染图像。

<p:dataTable id="dataTable" var="row" value="#{bean}"
             lazy="true"
             skipChildren="true">

    <p:column headerText="Image">
        <p:cellEditor>
            <f:facet name="output">
                <p:graphicImage value="#{imageBean.image}" stream="true" cache="true">
                    <f:param name="id" value="#{row.id}"/>
                    <f:param name="width" value="100"/>
                    <f:param name="height" value="100"/>
                </p:graphicImage>
            </f:facet>

            <f:facet name="input">
                <p:graphicImage value="#{imageBean.image}" stream="true" cache="true">
                    <f:param name="id" value="#{row.id}"/>
                    <f:param name="width" value="100"/>
                    <f:param name="height" value="100"/>
                </p:graphicImage>

                <!-- <p:overlayPanel> here for file upload -->
            </f:facet>
        </p:cellEditor>
    </p:column>

    <p:column headerText="Edit">
        <p:rowEditor/>
    </p:column>
</p:dataTable>

数据 table 可能在需要时包含其他重要的常用属性和列。

当这个 table 被(Ajaxically)更新时,所有图像都从数据库(或磁盘文件系统,如果使用)中获取,就好像它们根本没有被浏览器缓存一样,即使 cache 明确设置为 true (这是默认值)。这在 PrimeFaces 5.3 final 之前运行良好。

The migration guide 没有说明任何内容,但显然缓存 <p:graphicImage>.

发生了一些变化

有什么解决问题的建议吗?

在上面的示例中,如果 table 包含 5 行中的 5 个图像,例如,对 <p:dataTable> 进行的每次更新都会查询数据库 10 次(内联行除外编辑默认为当前行)这不应该发生,因为获取图像特别是从数据库中获取图像的成本非常高。


请求/响应 headers 使用 PrimeFaces 6.0 final(运行 在 WildFly 10.0.0 final 上),当向服务器发出初始请求以提供图像时(不起作用 - 图像未缓存)。

General
    Request URL:https://localhost:8443/ContextRoot/javax.faces.resource/dynamiccontent.properties.xhtml?ln=primefaces&v=6.0&pfdrid=aed903cc-daba-4822-a62b-888b9a0ef2ac&pfdrt=sc&id=14&width=100&height=100&pfdrid_c=true
    Request Method:GET
    Status Code:200 OK
    Remote Address:127.0.0.1:8443
Response Headers
    Cache-Control:max-age=29030400
    Connection:keep-alive
    Date:Sat, 23 Jul 2016 06:59:54 GMT
    Expires:Sun, 23 Jul 2017 06:59:54 GMT
    Server:WildFly/10
    Transfer-Encoding:chunked
    X-Powered-By:Undertow/1
Request Headers
    Accept:image/webp,image/*,*/*;q=0.8
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:en-US,en;q=0.8
    Connection:keep-alive
    Cookie:JSESSIONID=4AoRGa1IAPTB4KssnikbO9uUetcQpMupli8BkGga.om-f6b0ea3ad206; __utma=111872281.616526714.1454485589.1468749319.1468751735.4; __utmz=111872281.1454485589.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
    Host:localhost:8443
    Referer:https://localhost:8443/ContextRoot/admin/Brand
    User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Query String Parameters
    ln:primefaces
    v:6.0
    pfdrid:aed903cc-daba-4822-a62b-888b9a0ef2ac
    pfdrt:sc
    id:14
    width:100
    height:100
    pfdrid_c:true

请求/响应 headers 使用 PrimeFaces 5.3 final(运行 在 GlassFish 4.1 上),当向服务器发出初始请求以提供图像时(按预期工作 - 图像被缓存) .

General
    Request URL:https://localhost:8181/ContextRoot/javax.faces.resource/dynamiccontent.properties.xhtml?ln=primefaces&v=5.3&pfdrid=aAPHlxcQ2lcqfvzacYoCC6iUxLU1VVFp&pfdrt=sc&id=11&width=100&height=100&pfdrid_c=true
    Request Method:GET
    Status Code:200 OK
    Remote Address:127.0.0.1:8181
Response Headers
    Cache-Control:max-age=29030400
    Date:Sat, 23 Jul 2016 07:15:03 GMT
    Expires:Sun, 23 Jul 2017 07:15:04 GMT
    Pragma:No-cache
    Server:GlassFish Server Open Source Edition  4.1
    Transfer-Encoding:chunked
    X-Powered-By:Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition  4.1  Java/Oracle Corporation/1.8)
Request Headers
    Accept:image/webp,image/*,*/*;q=0.8
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:en-US,en;q=0.8
    Connection:keep-alive
    Cookie:JSESSIONID=69b5070218cfe0fc6eaac2141c13; __utma=111872281.616526714.1454485589.1468749319.1468751735.4; __utmz=111872281.1454485589.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
    Host:localhost:8181
    Referer:https://localhost:8181/ContextRoot/admin/Brand
    User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36
Query String Parameters
    ln:primefaces
    v:5.3
    pfdrid:aAPHlxcQ2lcqfvzacYoCC6iUxLU1VVFp
    pfdrt:sc
    id:11
    width:100
    height:100
    pfdrid_c:true

Headers好看。这表明查询字符串参数中的某些内容因请求而异。这也将被解释为一个全新的资源,因此即使基本 URI(URL 查询字符串分隔符 ? 之前的部分)完全相同,也会破坏缓存。

事实上,PrimeFaces 6.0 已经改变了 pfdrid 查询字符串参数的生成方式。它变成了一个完全随机的 UUID,每次渲染 HTML <img src> 时都会改变。另见 line 59 of PF 6.0 source code. In PrimeFaces 5.3, it was encrypted based on EL expression string and thus guaranteed to be the same across requests as long as the EL expression string is the same. See also line 53 of PF 5.3 source code.

更改为 introduced by Cagatay without a reference to an issue ticket. So it remains unclear why exactly this change was done. But after all it doesn't offer the client the opportunity anymore to cache the dynamic content and would thus actually decrease performance in both ends. This is definitely worth an issue ticket at PrimeFaces, so I created one: issue 1765

除了破解 PrimeFaces 源代码之外,我没有看到解决此问题的干净方法。最好的办法是将 <p:graphicImage> 替换为 <h:graphicImage> 和 "plain vanilla servlet",或者如果您碰巧使用 JSF 实用程序库 OmniFaces, then the <o:graphicImage> with a simple bean. Those approaches are already detailed in this related Q&A: Show image as byte[] from database as graphic image in JSF page.


更新:根据issue 1765,已针对 PrimeFaces 6.1 修复。

我在使用 primefaces to images 的这个组件时遇到了同样的问题,因为它添加了用于控制 Cache-Control

的参数 ?pfdrid_c=true

我是这样使用它的(primefaces 元素):

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:p="http://primefaces.org/ui"...>


<p:graphicImage value="/url/images" />

并且我选择使用另一个非常适合我的 jsf 元素,因为它不引入参数:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"...>


<h:graphicImage value="/url/images" />

正如@BalusC 所阐明的那样,仅当值是表示 URL.

的字符串时才有效