HTTP Caching
HTTP caching is a mechanism that stores responses associated with specific requests and reuses those stored responses for subsequent identical requests. This reduces the load on upstream servers and improves the performance of your infrastructure.
HTTP Cache Middleware
Goma Gateway’s HTTP Cache Middleware enables you to implement caching for your routes, ensuring faster response times and reduced server load. This middleware adheres to the standards outlined in RFC 7234 (HTTP/1.1 Caching).
HTTP Caching
- Cache Implementation: Enable HTTP caching for routes to improve response times and reduce server load.
- Cache Storage Options:
- In-Memory Cache: Suitable for single-instance applications or temporary caching.
- Redis Cache: Ideal for distributed caching across multiple instances.
- Cache Control Headers: Support for
Cache-Control,and X-Cache-Statusheaders for fine-grained cache management. -
Cache Invalidation: Implement strategies to invalidate stale cache entries (e.g., time-based or event-based invalidation).
Cache Status Header
The middleware adds a X-Cache-Status header to responses, indicating the cache status for each request. The possible values are:
- HIT: The response was served directly from the cache, and the request did not reach the upstream application.
- MISS: The response was fetched from the upstream application and not from the cache.
- BYPASS: The request or response did not meet the criteria for HTTP caching, so caching was bypassed.
When the status is BYPASS, an X-Goma-Cache-Reason header says which rule declined it — for example the response is marked no-store or the request carried credentials. The same reason is logged at info level the first time a route hits it, and at debug level afterwards, so a cache that never fills can be diagnosed without reading the source. X-Goma-Cache carries the same status and is not suppressed by disableCacheStatusHeader.
Middleware Configuration Options
The HTTP Cache Middleware provides the following configuration options:
-
maxTtl(integer, default=300):
The maximum time-to-live (in seconds) for cached responses. After this duration, cached responses expire and are invalidated. -
maxStale(integer, default=0):
Allows the middleware to serve stale responses if permitted by the request’sCache-Controldirective (max-stale). -
memoryLimit(string):
Specifies the maximum memory allocation for the cache. Supported units includeKi,Mi,Gi,Ti, orK,M,G,T(e.g.,1Mifor 1 megabyte). -
disableCacheStatusHeader(boolean):
When set totrue, prevents the middleware from adding theX-Cache-Statusheader to responses. -
excludedResponseCodes(array of strings):
Configures specific HTTP response status codes or ranges of codes for which caching is disabled. For example, you can exclude error responses like404or500-599. -
cachePrivateResponses(boolean, default=false):
Allows responses to requests that carried credentials to be cached, keyed per caller. See What is not cached before enabling it. -
ignoreVary(array of strings):
ResponseVaryfields to disregard. Use it for a backend that advertises aVaryits bodies do not actually honour: the field is then left out of the cache key, so every caller shares one entry instead of each getting their own.
What is not cached
The cache is shared by every caller of the route, so anything that would let one caller read another’s response stays out of it:
- Requests carrying credentials — an
Authorization,Proxy-AuthorizationorCookieheader — bypass the cache in both directions. SetcachePrivateResponses: trueto cache them anyway; the key then includes a fingerprint of those credentials, so each caller gets their own entry. - Responses that set a cookie, carry
WWW-Authenticate, or are markedCache-Control: private,no-storeorno-cache.no-cacheis refused rather than stored-and-revalidated because this cache has no conditional-request path, so a stored copy could never be served. - Responses with
Vary: *, or varying on more than three headers — past that, the same resource would occupy an unreasonable number of entries.
Responses that vary
A response with a Vary header is stored under a secondary key built from the request’s values for the fields it names, which is what RFC 9111 asks a cache to do. Two callers who differ on those fields get their own entry; callers who agree share one. The Vary is replayed on the cached response so caches downstream key on it too.
Three kinds of field never reach the key:
Accept-Encoding— already part of the base key.Authorization,Proxy-AuthorizationandCookie— a credentialed request never reads a shared entry in the first place, and undercachePrivateResponsesthe key already includes a fingerprint of them. AVarynaming them tells the cache nothing it has not already enforced. This matters in practice:raw.githubusercontent.com, for one, answersVary: Authorization, Accept-Encodingon public files that are identical for everyone.- Anything listed in
ignoreVary.
Cache key
The cache key is the route name, host, negotiated encoding, path, and — when enabled — the query parameters and the caller fingerprint, plus the secondary key described above when the response varies. Responses to credentialed requests are returned with Cache-Control: private so caches between Goma and the browser do not store them either.
An unsafe method (POST, PUT, DELETE) invalidates the entry for the base key and the one the same caller would have read. Entries stored for other callers’ Vary values are left to expire — they cannot be enumerated from a single request.
Example Configuration
Below is an example configuration for the HTTP Cache Middleware in YAML format:
middlewares:
- name: httpCache
type: httpCache
paths:
- ^/store/items/(.*)$
- /store/categories/.*
- /api/stores/(.*)/items/(.*)
rule:
maxTtl: 60
memoryLimit: 500Mi # Supported units: Ki, Mi, Gi, Ti or K, M, G, T
disableCacheStatusHeader: true
cacheableStatusCodes: [200, 203, 204, 300, 301, 302, 404]
excludedResponseCodes: [] # e.g., [500, 404]
includeQueryInKey: false # Whether to include query parameters in the cache key
queryParamsToCache: [] # List of specific query parameters to include in the cache key
ignoreVary: [] # Response Vary fields to leave out of the cache key
Notes
- Paths: The
pathsfield supports regex patterns for flexible route matching.
For example:
^/store/items/(.*)$matches paths starting with/store/items/./store/categories/.*matches all paths under/store/categories/./api/stores/(.*)/items/(.*)matches dynamic paths under/api/stores/.
Cache only specific query params
- Query Parameters: You can choose to include or exclude query parameters in the cache key. Use
includeQueryInKeyto enable or disable this feature, andqueryParamsToCacheto specify which query parameters should be considered for caching.
middlewares:
- name: httpCache
type: httpCache
paths:
- /v1/items
rule:
maxTtl: 300
memoryLimit: 500Mi # Supported units: Ki, Mi, Gi, Ti or K, M, G, T
disableCacheStatusHeader: true
cacheableStatusCodes: [200]
excludedResponseCodes: [] # e.g., [500, 404]
includeQueryInKey: true # Whether to include query parameters in the cache key
queryParamsToCache:
- page
- limit
- category
In this example, the HTTP Cache Middleware is configured to cache responses for the /v1/items endpoint. The cache will consider only the page, limit, and category query parameters when determining the cache key. This allows for more granular caching based on these specific parameters, while ignoring any other query parameters that may be present in the request.
/v1/items?page=1&utm_source=google=> cached as/v1/items?page=1/v1/items?page=2&session_id=xyz=> cached as/v1/items?page=2/v1/items?category=electronics&page=1→ cached as/v1/items?category=electronics&page=1