Play Framework 中的咖啡因缓存不会 return 缓存响应

Caffeine cache in Play Framework doesn't return cached responses

我在我的 java Play Framework 作业中使用 Caffeine 缓存实现来缓存传出的 http 请求,我发现尽管缓存已启动并且 运行,我的服务仍然每次都访问外部服务器,而不是从缓存中返回值。 而且我看到日志中记录的密钥总是相同的。

所以我看到 freshnessLifetime 没有设置,所以这可能意味着缓存立即过期。但我仍然不知道如何在配置中设置它

我没有更改我的 java 代码,如果我需要这样做,我找不到任何示例,或者我应该只有一个缓存配置适用于所有传出请求。

如有任何帮助,我将不胜感激

我的 build.sbt 包含:

libraryDependencies += ws
libraryDependencies += caffeine

我的 reference.conf 包含:

# Configuration settings for JSR 107 Cache for Play WS.
play.ws.cache {
  enabled = true
  heuristics.enabled = false
  name = "play-ws-cache"
}

我的 application.conf 包含:

# source https://github.com/ben-manes/caffeine/blob/master/jcache/src/main/resources/reference.conf
caffeine.jcache {
  # A named cache is configured by nesting a new definition under the caffeine.jcache namespace. The
  # per-cache configuration is overlaid on top of the default configuration.
  play-ws-cache {
    read-through {
      # If enabled, the entry is loaded automatically on a cache miss
      enabled = true
    }
    # The eviction policy for automatically removing entries from the cache
    policy {
      # The expiration threshold before lazily evicting an entry. This single threshold is reset on
      # every operation where a duration is specified. As expected by the specification, if an entry
      # expires but is not accessed and no resource constraints force eviction, then the expired
      # entry remains in place.
      lazy-expiration {
        # The duration before a read of an entry is considered expired. If set to 0 then the entry
        # is considered immediately expired. May be a time duration, null to indicate no change, or
        # "eternal" to indicate no expiration.
        access = 5m
      }
      # The expiration thresholds before eagerly evicting an entry. These settings correspond to the
      # expiration supported natively by Caffeine where expired entries are collected during
      # maintenance operations.
      eager-expiration {
        # Specifies that each entry should be automatically removed from the cache once a fixed
        # duration has elapsed after the entry's creation, the most recent replacement of its value,
        # or its last read. Access time is reset by all cache read and write operation. This setting
        # cannot be combined with the variable configuration.
        after-access = 5m
      }
      # The maximum bounding of the cache based upon its logical size
      maximum {
        # The maximum number of entries that can be held by the cache. This setting cannot be
        # combined with the weight configuration.
        size = 10000
      }
    }
  }
}

我在日志中看到:

[debug] - restclient.BaseRestClient - Executing GET with url http://localhost:9001/entities/v2/867386732 [trace] - p.a.l.w.a.c.CachingAsyncHttpClient - execute: request = Request(GET http://localhost:9001/entities/v2/867386732), handler = AsyncHandler(play.libs.ws.ahc.StandaloneAhcWSClient$ResponseAsyncCompletionHandler@65b0b233), future = null [debug] - p.a.libs.ws.ahc.cache.AhcHttpCache - get: key = GET http://localhost:9001/entities/v2/867386732 [debug] - p.a.l.w.a.c.CachingAsyncHttpClient - execute GET http://localhost:9001/entities/v2/867386732: results = List(ResponseEntry(CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:08 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1),GET,Map(),Some(2020-10-02T10:44:08.760450-07:00[America/Los_Angeles]))) [trace] - c.t.c.ResponseSelectionCalculator - findMatchingResponse: request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), responses = List(StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map())) [debug] - p.a.l.w.a.c.CachingAsyncHttpClient - execute GET http://localhost:9001/entities/v2/867386732: selected from cache: ResponseEntry(CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:08 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1),GET,Map(),Some(2020-10-02T10:44:08.760450-07:00[America/Los_Angeles])) [trace] - c.t.c.CurrentAgeCalculator - calculateCurrentAge(headers: TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)), now: 2020-10-01T17:44:38.690992Z[GMT], requestTime: 2020-10-01T17:44:38.690274Z[GMT], responseTime: 2020-10-01T17:44:38.690981Z[GMT]) [trace] - c.t.c.CurrentAgeCalculator

  • calculateCurrentAge: currentAge = PT30S [debug] - c.t.c.ResponseServingCalculator - serveResponse: response found for 'GET http://localhost:9001/entities/v2/867386732', age = 30 [trace] - c.t.c.ResponseServingCalculator - noCacheFound: request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), response = StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map()) [trace] - c.t.c.ResponseServingCalculator - isCachedResponseFresh: request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), response = StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map()) [trace] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: freshnessLifetime = None [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: result = PT0S [debug] - c.t.c.ResponseServingCalculator - isCachedResponseFresh: freshnessLifetime = PT0S, currentAge = PT30S [debug] - c.t.c.ResponseServingCalculator - isCachedResponseFresh: freshnessLifetime = PT0S, currentAge = PT30S [trace] - c.t.c.ResponseServingCalculator - isStaleResponseProhibited: request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), response = StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map()) [trace] - c.t.c.ResponseServingCalculator - isStaleResponseAllowed: PT30S, request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), response = StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map()) [debug] - c.t.c.ResponseServingCalculator - isStaleResponseAllowed: stale response not allowed [trace] - c.t.c.ResponseServingCalculator - canServeStaleAndRevalidate: response = StoredResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:08 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)),GET,Map()) [trace] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: freshnessLifetime = None [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: result = PT0S [trace] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: freshnessLifetime = None [debug] - c.t.c.FreshnessCalculator - calculateFreshnessLifetime: result = PT0S [debug] - p.a.l.w.a.c.CachingAsyncHttpClient - serveResponse GET http://localhost:9001/entities/v2/867386732: Response is stale, and stale response is not allowed -- revalidate with staleIfError = false [trace] - p.a.l.w.a.c.CachingAsyncHttpClient - buildValidationRequest: Request(GET http://localhost:9001/entities/v2/867386732), response = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:08 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [debug] - p.s.a.o.a.n.r.NettyRequestSender - Using pooled Channel '[id: 0x1fac35f7, L:/127.0.0.1:49899 - R:localhost/127.0.0.1:9001]' for 'GET' to 'http://localhost:9001/entities/v2/867386732' [debug] - p.s.a.o.a.n.r.NettyRequestSender - Using open Channel [id: 0x1fac35f7, L:/127.0.0.1:49899 - R:localhost/127.0.0.1:9001] for GET '/entities/v2/867386732' [trace] - p.s.a.i.n.h.logging.LoggingHandler
  • [id: 0x1fac35f7, L:/127.0.0.1:49899 - R:localhost/127.0.0.1:9001] WRITE: 107B

[debug] - p.s.a.o.a.netty.handler.HttpHandler -

Request DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: EmptyByteBufBE) GET /entities/v2/867386732 HTTP/1.1 host: localhost:9001 accept: / user-agent: AHC/2.1

Response DefaultHttpResponse(decodeResult: success, version: HTTP/1.1) HTTP/1.1 200 OK Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin X-Frame-Options: DENY X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff X-Permitted-Cross-Domain-Policies: master-only Date: Thu, 01 Oct 2020 17:44:38 GMT Content-Type: application/json Content-Length: 2144

[debug] - p.s.a.o.a.n.channel.ChannelManager - Adding key: http://localhost:9001 for channel [id: 0x1fac35f7, L:/127.0.0.1:49899

  • R:localhost/127.0.0.1:9001] [trace] - p.a.l.w.a.cache.AsyncCachingHandler - onCompleted: this = CacheAsyncHandler(key = GET http://localhost:9001/entities/v2/867386732, requestTime = 2020-10-01T17:44:38.692247Z[GMT], builder = play.api.libs.ws.ahc.cache.CacheableResponseBuilder@492a840f, asyncHandler = AsyncHandler(play.libs.ws.ahc.StandaloneAhcWSClient$ResponseAsyncCompletionHandler@65b0b233)}) [debug] - p.a.l.w.a.cache.AsyncCachingHandler - onCompleted: response = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [trace] - p.a.libs.ws.ahc.cache.AhcHttpCache - invalidate: request = Request(GET http://localhost:9001/entities/v2/867386732), response = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [debug] - p.a.l.w.a.cache.AsyncCachingHandler - processFullResponse: fullResponse = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [trace] - c.t.c.ResponseCachingCalculator - isCacheable: request: CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), response = OriginResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:38 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only))) [trace] - c.t.c.ResponseCachingCalculator - responseIsCacheable: response = OriginResponse(http://localhost:9001/entities/v2/867386732,200,TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:38 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only))) [trace] - c.t.c.ResponseCachingCalculator - isCacheable: result = DoCacheResponse(Response status code 200 is cacheable by default) [debug] - p.a.l.w.a.cache.AsyncCachingHandler - isCacheable: DO CACHE, because Response status code 200 is cacheable by default [debug] - p.a.libs.ws.ahc.cache.AhcHttpCache - cacheResponse: response = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [debug] - p.a.libs.ws.ahc.cache.AhcHttpCache - cacheResponse: strippedResponse = CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1) [trace] - c.t.c.SecondaryKeyCalculator - calculate: request = CacheRequest(http://localhost:9001/entities/v2/867386732,GET,TreeMap()), responseHeaders = TreeMap(Date -> List(Thu, 01 Oct 2020 17:44:38 GMT), Content-Type -> List(application/json), Content-Length -> List(2144), Referrer-Policy -> List(origin-when-cross-origin, strict-origin-when-cross-origin), X-Frame-Options -> List(DENY), X-XSS-Protection -> List(1; mode=block), X-Content-Type-Options -> List(nosniff), X-Permitted-Cross-Domain-Policies -> List(master-only)) [debug] - p.a.libs.ws.ahc.cache.AhcHttpCache - put: key = GET http://localhost:9001/entities/v2/867386732, entry = ResponseEntry(CacheableResponse(status = CacheableHttpResponseStatus(code = 200, text = OK), headers = DefaultHttpHeaders[Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin, X-Frame-Options: DENY, X-XSS-Protection: 1; mode=block, X-Content-Type-Options: nosniff, X-Permitted-Cross-Domain-Policies: master-only, Date: Thu, 01 Oct 2020 17:44:38 GMT, Content-Type: application/json, Content-Length: 2144], bodyParts size = 1),GET,Map(),Some(2020-10-02T10:44:38.771750-07:00[America/Los_Angeles])) [debug] - restclient.BaseRestClient - Response status [200] for url [http://localhost:9001/entities/v2/867386732] [trace] - p.s.a.i.n.h.logging.LoggingHandler - [id: 0x1fac35f7, L:/127.0.0.1:49899 - R:localhost/127.0.0.1:9001] READ COMPLETE [trace]
  • p.a.l.w.ahc.cache.CacheableResponse - getResponseBody:

我真的找到了它是如何工作的。缓存不应该像 Redis 或 Memcached 这样的单独服务那样管理生命周期,而是像浏览器一样运行,并由 HTTP 响应中的 headers 管理。 这里:https://github.com/playframework/cachecontrol/blob/e4694aa0665e2ccc5030ae1cf1d0b15ad5b98471/src/main/scala/com/typesafe/play/cachecontrol/FreshnessCalculator.scala#L42

所以对我来说解决方案是更改服务器以使其正常服务header:Cache-Control "max-age=3600, public"