PrimeFaces 6.0 не кэширует изображения на стороне клиента

Учитывая <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>

Таблица данных может содержать другие важные часто используемые атрибуты и столбцы по мере необходимости.

Когда эта таблица (Ajaxically) обновляется, все изображения выбираются из базы данных (или файловой системы диска, если используется), как будто они вообще не кэшируются браузером, даже если cache явно установлен на true (который является значением по умолчанию). Это хорошо работало до финала PrimeFaces 5.3.

Руководство по миграции ничего не говорит об этом, но, видимо, что-то изменилось в кэшировании <p:graphicImage>,

Любое предложение, чтобы решить проблему?

Например, в приведенном выше примере, если таблица содержит 5 изображений в 5 строках, база данных будет запрашиваться 10 раз при каждом обновлении <p:dataTable> (кроме встроенного редактирования строки, по умолчанию текущей строки), что не должно происходить, поскольку получение изображений, особенно из базы данных, очень дорого.


Заголовки запроса / ответа, использующие 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

Заголовки запроса / ответа, использующие 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

1 ответ

Решение

Заголовки выглядят хорошо. Это говорит о том, что что-то в параметрах строки запроса изменяется от запроса к запросу. Это также будет интерпретироваться как совершенно новый ресурс и, таким образом, разрушит кэширование, даже если базовый URI (часть перед разделителем строки запроса URL) ?) точно так же.

И действительно, PrimeFaces 6.0 изменил способ pfdrid Параметр строки запроса генерируется. Это стало совершенно случайным UUID который меняется каждый раз, когда HTML <img src> оказано. Смотрите также строку 59 исходного кода PF 6.0. В PrimeFaces 5.3 он был зашифрован на основе строки выражения EL и, таким образом, гарантированно будет одинаковым в запросах, если строка выражения EL одинакова. См. Также строку 53 исходного кода PF 5.3.

Изменение было введено Cagatay без ссылки на тикет. Так что остается неясным, почему именно это изменение было сделано. Но, в конце концов, это больше не дает клиенту возможности кэшировать динамический контент и, таким образом, фактически снижает производительность в обоих концах. На PrimeFaces это определенно стоит билет для выпуска, поэтому я его создал: выпуск 1765.

Я не вижу чистого способа решить эту проблему, кроме как взломать исходный код PrimeFaces. Ваш лучший выбор - заменить <p:graphicImage> по <h:graphicImage> с "простым ванильным сервлетом", или если вы используете библиотеку утилит JSF OmniFaces, то <o:graphicImage> с простым бобом. Эти подходы уже подробно описаны в соответствующих вопросах и ответах: Показать изображение в виде байта [] из базы данных в виде графического изображения на странице JSF.


Обновление: согласно проблеме 1765, это было исправлено для PrimeFaces 6.1.

У меня была такая же проблема с этим компонентом простых шрифтов для изображений, потому что он добавляет параметр ?pfdrid_c=true используется для контроля Cache-Control

Я использовал это так (элемент 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-адрес.

Другие вопросы по тегам