Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Spring MVC private Cache-Control: decide who may retain a receipt

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Cache-Control on a personalized response sets the storage boundary; a valid ETag alone does not make a tenant receipt safe for a shared cache.

Bind the cache decision to the data

A receipt total is visible only to the authenticated tenant. A browser may keep a short-lived copy if product policy permits it, but an intermediary must not reuse the response for another user. Set a private directive on the response, and decide separately whether sensitive fields require no-store. Conditional GET] saves response bytes after authorization; it is not an authorization check.

Validate before a conditional response

A client may send If-None-Match for a receipt it no longer owns. Resolve the tenant and authorize that receipt before computing the entity tag or returning 304. Scope the tag to the representation and tenant; changing visibility or serialization must change the validator. A private cache can still retain data on a shared device, so use no-store for a receipt that must leave no local copy.

Test through the full path

Request the same receipt as its owner and as a second tenant, including a matching If-None-Match header. The owner may receive 304 after a prior 200; the second tenant must never get a revealing 304. Inspect Cache-Control on both 200 and 304. If a reverse proxy rewrites headers, test that deployed edge as well.

Implementation contract

Java
@GetMapping("/receipts/{receiptId}")
ResponseEntity<ReceiptView> readReceipt(
        @PathVariable UUID receiptId, Authentication authentication) {
    ReceiptView receipt = receiptService.authorizedView(authentication, receiptId);
    return ResponseEntity.ok()
        .cacheControl(CacheControl.maxAge(Duration.ofMinutes(2)).cachePrivate())
        .eTag("\"" + receipt.representationVersion() + "\"")
        .body(receipt);
}

Cost and verification

A short private cache can reduce repeated transfer and rendering. ETag calculation still costs enough to load the authorized version; no-store trades this saving for tighter data retention.

Common Mistakes

  • Do not mark tenant-specific receipts public.
  • Do not emit a 304 before checking current authorization.
  • Do not use a stable ETag when the visible representation or permissions changed.

Read next

Spring MVC conditional GET: validate the representation tag, Spring MVC consumes and produces: 415 and 406 are different failures, Spring Security filter chain: authentication, CSRF and request order, Spring MVC byte ranges: resume an authorized receipt download, Spring MVC Content-Disposition: produce a safe attachment filename.

spring
spring-web
mvc-private-receipt-cache-policy
Storage details