PrimeFaces 6.0 does not cache images on the client side
Asked Answered
J

2

8

Given a <p:dataTable> rendering images in one of the columns.

<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>

The data table may contain other essential commonly used attributes and columns as and when needed.

When this table is (Ajaxically) updated, all images are fetched from the database (or disk file system, if used) as if they are not cached by the browser at all even though cache is explicitly set to true (which is the default value). This was working well previoulsly with PrimeFaces 5.3 final.

The migration guide states nothing about it but apparently something has been changed about caching <p:graphicImage>.

Any suggestion to fix the problem?

In the example above, if the table contains 5 images in 5 rows, for example, the database will be queried 10 times on every single update made to the <p:dataTable> (except inline row editing which defaults to the current row) which should not happen as getting images especially from a database is very costly.


Request / response headers using PrimeFaces 6.0 final (running on WildFly 10.0.0 final), when an initial request is made to the server to serve an image (does not work - images are not cached).

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

Request / response headers using PrimeFaces 5.3 final (running on GlassFish 4.1), when an initial request is made to the server to serve an image (works as intended - images are cached).

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
Jarmon answered 22/7, 2016 at 14:22 Comment(3)
Did you inspect network traffic of the initial reponse? Any headers there that might indicate a next request will not come frome the cache?Salerno
Requests to download images from the database are visible in the HTTP network traffic monitor. There are separate requests listed in the network traffic monitor and all images are queried from the database every time an AJAX request updating the given <p:dataTable> is made which is also visible on the server side by viewing the corresponding SQL statements generated by the Hibernate log.Jarmon
I meat the http cache headers... is "something" present? Wrong values?Salerno
A
11

Headers look good. This suggests that something in query string parameters changes from request to request. This would also be interpreted as a brand new resource and thus bust the caching even though the base URI (the part before URL query string separator ?) is exactly the same.

And indeed, PrimeFaces 6.0 has changed the way how the pfdrid query string parameter is generated. It has become a completely random UUID which changes every time when the HTML <img src> is rendered. See also 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.

The change was 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.

I'm not seeing a clean way to solve this other than hacking the PrimeFaces source code. Your best bet is to replace the <p:graphicImage> by a <h:graphicImage> with a "plain vanilla servlet", or if you happen to use JSF utility library 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.


Update: as per issue 1765, it has been fixed for PrimeFaces 6.1.

Autum answered 17/9, 2016 at 7:17 Comment(1)
The fix of issue 1765 will not fix the case, when you use images across pages. I opened a new followup Issue 2097Fugacious
T
-1

I have had the same problem with this component of primefaces to images, because it adds the parameter ?pfdrid_c=true used to control the Cache-Control

I was using it like this (primefaces element):

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


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

and I chose to use this other jsf element that works perfectly for me since it does not introduce parameter:

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


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

As clarified very well @BalusC this works only if the value is a String representing an URL.

Tyndale answered 30/9, 2019 at 11:54 Comment(1)
This works only if the value is a String representing an URL. But this does not work if the value is a DefaultStreamedContent. This isn't supported by <h:graphicImage>. So you're not correctly answering the question.Autum

© 2022 - 2024 — McMap. All rights reserved.