Вопрос по rest, jersey, java, jax-rs – Джерси: по умолчанию контроль кэша не кэшируется

20

При написании веб-службы RESTful у меня возникают проблемы, если я включаю кэширование на моем клиенте (в настоящее время - толстый клиент .NET). По умолчанию Jersey не отправляет какой-либо заголовок элемента управления кэшем, поэтому клиент автоматически кэширует большинство страниц (что, по-видимому, является допустимым поведением).

Я хотел бы, чтобы Джерси по умолчанию отправлял элемент управления кэшем «no-cache», а затем, в частности, ответы переопределяли элемент управления кэшем.

Есть ли способ сделать это с Джерси?

Я обнаружил, что RESTeasy имеет возможность использовать аннотацию @NoCache, чтобы задать настройку для всего класса, но я не нашел ничего похожего на Джерси.

Ваш Ответ

5   ответов
2

Я думаю, что вы можете использовать

isNoCache(true)

который остановит кеширование в браузере.

Увидеть:

http://jersey.java.net/nonav/apidocs/1.12/jersey/javax/ws/rs/core/CacheControl.html#isNoCache%28%29

Надеюсь это поможет.

Да, я могу сделать это в одном отдельном ответе, я надеялся получить что-то на более высоком / более общем уровне. Pete
23

создать любую пользовательскую аннотацию, которую вы прикрепляете к вашим методам, чтобы установить настройки управления кэшем. ResourceFilterFactories вызывается для каждого обнаруженного метода ресурса при инициализации приложения - в вашей ResourceFilterFactory вы можете проверить, есть ли у метода аннотация @CacheControlHeader (или как вы хотите ее вызывать) - если нет, просто верните фильтр ответа, который добавляет & quot; no- кэш & Quot; указание на ответ, в противном случае следует использовать настройки из аннотации. Вот пример того, как это сделать:

public class CacheFilterFactory implements ResourceFilterFactory {
    private static final List<ResourceFilter> NO_CACHE_FILTER = Collections.<ResourceFilter>singletonList(new CacheResponseFilter("no-cache"));

    @Override
    public List<ResourceFilter> create(AbstractMethod am) {
        CacheControlHeader cch = am.getAnnotation(CacheControlHeader.class);
        if (cch == null) {
            return NO_CACHE_FILTER;
        } else {
            return Collections.<ResourceFilter>singletonList(new CacheResponseFilter(cch.value()));
        }
    }

    private static class CacheResponseFilter implements ResourceFilter, ContainerResponseFilter {
        private final String headerValue;

        CacheResponseFilter(String headerValue) {
            this.headerValue = headerValue;
        }

        @Override
        public ContainerRequestFilter getRequestFilter() {
            return null;
        }

        @Override
        public ContainerResponseFilter getResponseFilter() {
            return this;
        }

        @Override
        public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
            // attache Cache Control header to each response based on the annotation value
            response.getHttpHeaders().putSingle(HttpHeaders.CACHE_CONTROL, headerValue);
            return response;
        }
    }
}

Аннотация может выглядеть так:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControlHeader {
    String value();
}

ResourceFilterFactory можно зарегистрировать в вашем приложении, добавив следующий параметр init в определение сервлета Джерси в файле web.xml:

<init-param>
    <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
    <param-value>package.name.CacheFilterFactory</param-value>
</init-param>
Спасибо, что подвели итоги. Я сам поковырялся в этом, но это право отлично суммирует «Правильный путь». сделать это. Pete
Есть ли способ установить управление кэшем без кэширования для всех методов, не добавляя аннотацию для каждого?
Cache-Control Using Annotations With Jersey намного чище и полнее
Обратите внимание, что это решение применимо только к версии 1.x на Джерси. В Jersey 2.x нет класса ResourceFilters, пакет - org.glassfish.jersey против com.sun.jersey и т. Д. В способе Jersey 2.x для этого используется javax.ws.rs.container.ContainerResponseFilter.
14

@NoCache без кеширования вообще и одного@CacheMaxAge для конкретного кеширования.CacheMaxAge принимает два аргумента, поэтому вам не нужно вычислять секунды самостоятельно:

@GET
@CacheMaxAge(time = 10, unit = TimeUnit.MINUTES)
@Path("/awesome")
public String returnSomethingAwesome() {
    ...
}

ResourceFilter теперь имеет этот метод create, который по умолчанию не мешает (поэтому другие механизмы кэширования продолжают работать):

@Override
public List<ResourceFilter> create(AbstractMethod am) {
    if (am.isAnnotationPresent(CacheMaxAge.class)) {
        CacheMaxAge maxAge = am.getAnnotation(CacheMaxAge.class);
        return newCacheFilter("max-age: " + maxAge.unit().toSeconds(maxAge.time()));
    } else if (am.isAnnotationPresent(NoCache.class)) {
        return newCacheFilter("no-cache");
    } else {
        return Collections.emptyList();
    }
}

private List<ResourceFilter> newCacheFilter(String content) {
    return Collections
            .<ResourceFilter> singletonList(new CacheResponseFilter(content));
}

Вы можете увидеть полное решениев моем блоге.

Спасибо за решение, Мартин!

7

так как ResourceFilterFactory и ResourceFilter были удалены. Решение может быть адаптировано к JAX-RS 2.0 следующим образом.

Аннотация:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControlHeader {
  String value();
}

DynamicFeature:

@Provider
public class CacheFilterFactory implements DynamicFeature {

  private static final CacheResponseFilter NO_CACHE_FILTER = 
          new CacheResponseFilter("no-cache");

  @Override
  public void configure(ResourceInfo resourceInfo, 
                        FeatureContext featureContext) {

    CacheControlHeader cch = resourceInfo.getResourceMethod()
            .getAnnotation(CacheControlHeader.class);
    if (cch == null) {
      featureContext.register(NO_CACHE_FILTER);
    } else {
      featureContext.register(new CacheResponseFilter(cch.value()));
    }
  }

  private static class CacheResponseFilter implements ContainerResponseFilter {
    private final String headerValue;

    CacheResponseFilter(String headerValue) {
      this.headerValue = headerValue;
    }

    @Override
    public void filter(ContainerRequestContext containerRequestContext,
                       ContainerResponseContext containerResponseContext) {
      // attache Cache Control header to each response
      // based on the annotation value                     
      containerResponseContext
              .getHeaders()
              .putSingle(HttpHeaders.CACHE_CONTROL, headerValue);
    }

  }
}

CacheFilterFactory должен быть зарегистрирован в Джерси. Я делаю это с помощью Dropwizard - с помощью environment.jersey (). Register () - но в автономных системах я понимаю, что это можно сделать, например, разрешив Джерси сканировать ваши классы на аннотации @Provider, определив следующее в вашем файле web.xml. :

<servlet>
    <servlet-name>my.package.MyApplication</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

    <!-- Register resources and providers under my.package. -->
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>my.package</param-value>
    </init-param>
</servlet>

Увидетьэта почта для получения дополнительной информации о регистрации компонентов.

0

которая может отключить кеширование. Вы можете использовать следующую аннотацию для вашего API:

@CacheControl(noCache = true)

Ref: Джерси Аннотация для управления кешем

Вы ссылаетесь на класс org.springframework.http.CacheControl из Spring, который также не является аннотацией. Возможно, вы имели в виду javax.ws.rs.core.CacheControl, который также не является аннотацией.

Похожие вопросы