httpcache is a Go package that provides a standards-compliant http.RoundTripper for transparent HTTP response caching, following RFC 9111 (HTTP Caching).
FeaturesNote: This package is intended for use as a private (client-side) cache. It is not a shared or proxy cache. It is designed to be used with an HTTP client to cache responses from origin servers, improving performance and reducing load on those servers.
stale-while-revalidate
, stale-if-error
, and immutable
(view details).Demonstration of HTTP caching in action. See _examples/app for code.
InstallationTo install the package, run:
go get github.com/bartventer/httpcache
Quick Start
To get started, create a new HTTP client with the httpcache
transport, specifying a cache backend DSN. You'll need to register the desired cache backend before using it. Here's an example using the built-in file system cache:
package main
import (
"log/slog"
"net/http"
"time"
"github.com/bartventer/httpcache"
// Register the file system cache backend
_ "github.com/bartventer/httpcache/store/fscache"
)
func main() {
// Example DSN for the file system cache backend
dsn := "fscache://?appname=myapp"
client := &http.Client{
Transport: httpcache.NewTransport(
dsn,
httpcache.WithSWRTimeout(10*time.Second),
httpcache.WithLogger(slog.Default()),
),
}
// ... Use the client as usual
}
Cache BackendsNote: The DSN format and options depend on the cache backend you choose. Refer to the Cache Backends section for details on available backends and their DSN formats.
The following built-in cache backends are available:
Backend DSN Example Descriptionfscache
fscache://?appname=myapp
File system cache, stores responses on disk. Suitable for persistent caching across restarts. Supports context cancellation, as well as optional AES-GCM
encryption. memcache
memcache://
In-memory cache, suitable for ephemeral caching. Does not persist across restarts.
Consult the documentation for each backend for specific configuration options and usage details.
Custom Cache BackendsTo implement a custom cache backend, create a type that satisfies the store/driver.Conn
interface, then register it using the store.Register
function. Refer to the built-in backends for examples of how to implement this interface.
A REST API is available for cache inspection and maintenance, intended for debugging and development use only. Do not expose these endpoints in production.
Endpoints:
GET /debug/httpcache
— List cache keys (if supported)GET /debug/httpcache/{key}
— Retrieve a cache entryDELETE /debug/httpcache/{key}
— Delete a cache entryAll endpoints require a dsn
query parameter to select the cache backend.
Usage Example:
import (
"net/http"
"github.com/bartventer/httpcache/store/expapi"
)
func main() {
expapi.Register()
http.ListenAndServe(":8080", nil)
}
To use a custom ServeMux, pass expapi.WithServeMux(mux)
to expapi.Register()
.
WithUpstream(http.RoundTripper)
Set a custom transport for upstream/origin requests http.DefaultTransport
WithSWRTimeout(time.Duration)
Set the stale-while-revalidate timeout 5 * time.Second
WithLogger(*slog.Logger)
Set a logger for debug output slog.New(slog.DiscardHandler)
This package sets a cache status header on every response:
X-Httpcache-Status
: The primary, detailed cache status header (always set).X-From-Cache
: (Legacy) Provided for compatibility with gregjones/httpcache
. Only set for cache hits/stale/revalidated responses.HTTP/1.1 200 OK
X-Httpcache-Status: STALE
X-From-Cache: 1
Content-Type: application/json
Limitations
Range Requests & Partial Content: This cache does not support HTTP range requests or partial/incomplete responses (e.g., status code 206, Range
/Content-Range
headers). All requests with a Range
header are bypassed, and 206 responses are not cached. For example:
GET /example.txt HTTP/1.1
Host: example.com
Range: bytes=0-99
The above request will bypass the cache and fetch the response directly from the origin server. See RFC 9111 §3.3-3.4 for details.
Legend for Requirements:
Requirement Description Required Must be implemented for RFC compliance Optional May be implemented, but not required for compliance Obsolete Directive is no longer relevant as per RFC 9111 Deprecated Directive is deprecated as per RFC 9111, but can still be implemented N/A Nothing to implement or not applicable to private caches §3. Storing Responses in Caches (Details) § Title Requirement Implemented Notes 3.1. Storing Header and Trailer Fields Required ✔️ 3.2. Updating Stored Header Fields Required ✔️ 3.3. Storing Incomplete Responses Optional ❌ See Limitations 3.4. Combining Partial Content Optional ❌ See Limitations 3.5. Storing Responses to Authenticated Requests N/A N/A Not applicable to private client-side caches §4. Constructing Responses from Caches (Details) § Title Requirement Implemented Notes 4.1. Calculating Cache Keys with the Vary Header Field Required ✔️ 4.2. Freshness Required ✔️ Details §4.2. Freshness (Subsections) § Title Requirement Implemented Notes 4.2.1. Calculating Freshness Lifetime Required ✔️ 4.2.2. Calculating Heuristic Freshness Required ✔️ 4.2.3. Calculating Age Required ✔️ 4.2.4. Serving Stale Responses Required ✔️ § Title Requirement Implemented Notes 4.3. Validation Required ✔️ Details §4.3. Validation (Subsections) § Title Requirement Implemented Notes 4.3.1. Sending a Validation Request Required ✔️ 4.3.2. Handling Received Validation Request N/A N/A Not applicable to private client-side caches 4.3.3. Handling a Validation Response Required ✔️ 4.3.4. Freshening Stored Responses upon Validation Required ✔️ 4.3.5. Freshening Responses with HEAD Optional ❌ Pointless, rather use conditional GETs; see RFC 9110 §13.2.1 last para § Title Requirement Implemented Notes 4.4. Invalidating Stored Responses Required ✔️ §5. Field Definitions (Details) § Title Requirement Implemented Notes 5.1. Age Required ✔️ 5.2. Cache-Control Required ✔️ Details 5.3. Expires Required ✔️ 5.4. Pragma Deprecated ❌ Deprecated by RFC 9111; not implemented 5.5. Warning Obsolete ❌ Obsoleted by RFC 9111; not implemented §5.2. Cache-Control Directives § Title Requirement Implemented Notes 5.2.1. Request Directives Optional ✔️ Details §5.2.1. Request Directives (Details) § Title/Directive Requirement Implemented Notes 5.2.1.1.max-age
Optional ✔️ 5.2.1.2. max-stale
Optional ✔️ 5.2.1.3. min-fresh
Optional ✔️ 5.2.1.4. no-cache
Optional ✔️ 5.2.1.5. no-store
Optional ✔️ 5.2.1.6. no-transform
Optional ✔️ Compliant by default - implementation never transforms content 5.2.1.7. only-if-cached
Optional ✔️ Section Requirement Implemented Notes 5.2.2. Response Directives Required ✔️ Details §5.2.2. Response Directives (Details) § Title/Directive Requirement Implemented Notes 5.2.2.1. max-age
Required ✔️ 5.2.2.2. must-revalidate
Required ✔️ 5.2.2.3. must-understand
Required ✔️ 5.2.2.4. no-cache
Required ✔️ Both qualified and unqualified forms supported 5.2.2.5. no-store
Required ✔️ 5.2.2.6. no-transform
Required ✔️ Compliant by default - implementation never transforms content 5.2.2.7. private
N/A N/A Intended for shared caches; not applicable to private caches 5.2.2.8. proxy-revalidate
N/A N/A Intended for shared caches; not applicable to private caches 5.2.2.9. public
Optional ✔️ 5.2.2.10. s-maxage
N/A N/A Intended for shared caches; not applicable to private caches § Title Requirement Implemented Notes 5.2.3. Extension Directives Optional partially Details §5.2.3. Extension Directives (Details)
The following additional cache control directives are supported, as defined in various RFCs:
Reference Directive Notes RFC 5861, §3stale-while-revalidate
Only applies to responses RFC 5861, §4 stale-if-error
Applies to both requests and responses RFC 8246, §2 immutable
Only applies to responses License
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
Notes[^1]: No configuration is needed beyond the cache backend DSN. Caching is handled automatically based on HTTP headers and directives. To use a custom upstream transport, pass it with the WithUpstream
option. This lets you add httpcache
to your existing HTTP client with minimal changes. See Options for details.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4