web-dev-qa-db-ja.com

ジャージー:デフォルトのキャッシュ制御はキャッシュなし

RESTful Webサービスを作成しているときに、クライアント(現在は.NETシッククライアント)で何らかのキャッシュを有効にすると、問題が発生します。デフォルトでは、Jerseyはいかなる種類のキャッシュ制御ヘッダーも送信しないため、クライアントはほとんどのページを自動的にキャッシュします(これは有効な動作のようです)。

ジャージーにデフォルトで「キャッシュなし」のキャッシュ制御を送信させたいのですが、特に応答がキャッシュ制御をオーバーライドします。

ジャージーでこれを行う方法はありますか?

RESTeasyには@NoCacheアノテーションを使用してクラス全体の設定を指定する機能があることがわかりましたが、Jerseyに似たものは見つかりませんでした。

20
Pete

これは、ResourceFilterFactoryを使用することでJerseyで簡単に行えます。メソッドにアタッチするカスタムアノテーションを作成して、キャッシュ制御設定を設定できます。 ResourceFilterFactoriesは、アプリケーションが初期化されるときに、検出されたリソースメソッドごとに呼び出されます-ResourceFilterFactoryで、メソッドに@CacheControlHeaderアノテーション(または呼び出したいもの)があるかどうかを確認できます-ない場合は、「no-cache」を追加する応答フィルターを返すだけです。 "応答へのディレクティブ。それ以外の場合は、アノテーションの設定を使用する必要があります。これを行う方法の例を次に示します。

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は、web.xmlのJerseyサーブレットの定義に次のinitパラメーターを追加することでアプリケーションに登録できます。

<init-param>
    <param-name>com.Sun.jersey.spi.container.ResourceFilters</param-name>
    <param-value>package.name.CacheFilterFactory</param-value>
</init-param>
23
Martin Matula

@ martin-matulaによるソリューションに基づいて、2つのキャッシュアノテーションを作成しました。 1 @NoCacheキャッシュがまったくない場合と1つ@CacheMaxAge特定のキャッシュ用。 CacheMaxAgeは2つの引数を取るため、自分で秒を計算する必要はありません。

@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));
}

あなたは完全な解決策を見ることができます 私のブログ投稿で

マーティンの解決策をありがとう!

14
Alex

@ martin-matulaのソリューションは、ResourceFilterFactoryとResourceFilterが削除されているため、JAX-RS 2.0/Jersey2.xでは機能しません。このソリューションは、次のようにJAX-RS2.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をJerseyに登録する必要があります。私はDropwizardを介して(environment.jersey()。register()を使用して)それを行っていますが、スタンドアロンシステムでは、たとえば、web.xmlで以下を定義することにより、Jerseyに@Providerアノテーションのクラスをスキャンさせることでこれを行うことができることを理解しています:

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

コンポーネントの登録の詳細については、 この投稿 を参照してください。

7
JanneK

私はあなたが使うことができると思います

isNoCache(true)

これにより、ブラウザでのキャッシュが停止します。

見る:

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

お役に立てれば。

2
Joe

キャッシュを無効にできる注釈が1つ見つかりました。 APIには次のアノテーションを使用できます。

@CacheControl(noCache = true)

参照: キャッシュ制御用のJerseyアノテーション

0
Sahil Bhavsar