Dated report · 10 Oct 2026 · HTTP semantics and caching
POST response caching and unsafe-request invalidation
The narrow HTTP permission for a POST response to serve a later GET or HEAD is separate from the rule that an unsafe POST must be forwarded and can invalidate stored responses.
Bottom line
Under RFC 9110 §9.3.3, a response to POST meets the method-specific caching condition only when it contains explicit freshness information and a Content-Location with the same value as the request's target URI. If that response is stored and all other requirements allow reuse, it may satisfy a later GET or HEAD for that URI; it must not satisfy a later POST. RFC permissions do not prove that an implementation stored or reused it.
Separately, RFC 9111 requires a cache to write an unsafe request through before it responds. After a 2xx or 3xx response, that cache must invalidate stored response(s) for the target URI. The rule affects only caches traversed by the request; it is not global.
POST response eligibility: both specific conditions are required
| Condition | What qualifies | What does not qualify by itself |
|---|---|---|
| Explicit freshness | A response freshness lifetime such as Cache-Control: max-age=60 or Expires. For shared caches, s-maxage is also an explicit freshness input. | public alone does not give a freshness lifetime. Heuristic freshness is assigned in the absence of explicit expiration; it does not substitute for the POST-specific explicit-freshness condition. |
| Same-target Content-Location | The response's Content-Location value is the same as the POST target URI. Using the same absolute URI makes the example unambiguous. | A missing or different value fails the condition. Content-Location is representation metadata; it does not replace the target URI or itself prove a cache key. |
These two conditions make the response eligible under the POST-specific rule; they do not guarantee storage. RFC 9111 §2 makes caching optional. General requirements still apply: for example, the cache must understand the method, the response must be final, storage must not be prohibited by no-store, and target, method, response matching, freshness, and other applicable constraints must permit reuse.
What a stored POST response may answer
- Later GET: may be satisfied if the response was stored and normal reuse requirements hold.
- Later HEAD: may be satisfied on the same basis.
- Later POST: not from that stored POST response.
POST is potentially unsafe. A cache cannot treat an unsafe POST as a retrieval of the stored response.
What the cache must do with unsafe requests
- Before replying: forward the unsafe request and receive a corresponding response.
- 2xx or 3xx: invalidate stored responses for the request target URI.
- 4xx or 5xx: the §4.4 mandatory invalidation trigger is not met. This does not prohibit eviction for another reason.
Invalidation can remove stored responses or mark them invalid so mandatory validation is required before later use. It does not say whether the newly received POST response is retained.
Synthetic header example
This example uses the reserved .invalid domain and is illustrative only. It was not sent over the network.
POST /preview HTTP/1.1
Host: example.invalid
Content-Type: application/json
{"x":1}
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=60
Content-Location: https://example.invalid/preview
{"result":2}
The request target is https://example.invalid/preview. The response supplies a 60-second explicit freshness lifetime and a same-target Content-Location. Assuming the general storage and reuse requirements also hold, it may be reused for a later GET or HEAD while reusable. It does not establish that any cache stored it, will return it, or should place sensitive output in shared storage.
Expected-only synthetic matrix
Not observations: every row below is an RFC-based expectation, not an observed cache result. For POST-response rows, assume a final response, a cache that understands POST, no no-store, and no other constraint prohibiting storage unless a row says otherwise.
| Synthetic case | Expected protocol result | Boundary |
|---|---|---|
Explicit freshness plus same-target Content-Location; later GET | May satisfy GET if stored and otherwise reusable. | Eligibility is not a required cache hit. |
Same qualifying response; later HEAD | May satisfy HEAD if stored and otherwise reusable. | No implementation behavior is inferred. |
Same qualifying response; later POST | Must not be answered from that stored POST response; the unsafe request is written through. | GET/HEAD permission does not extend to POST. |
Same-target Content-Location, but only public and no explicit freshness | Fails the POST-specific cacheability condition. | public alone supplies no explicit freshness lifetime. |
Explicit freshness, but no Content-Location or a different value | Fails the POST-specific cacheability condition. | Content-Location must match the target URI. |
| Unsafe POST gets a 2xx or 3xx at a cache it traverses | It is written through; that cache must invalidate its stored response(s) for the target URI. | Does not establish retention of the newly received response. |
| Unsafe POST gets a 4xx or 5xx | It is still written through; §4.4 does not require target-URI invalidation on this error response. | Other/local eviction can still occur. |
| Another cache holds a response but the request never traverses it | This request does not trigger §4.4 invalidation at that cache. | RFC invalidation is not global. |
Keep the two rules separate
Do not shorten the result to “POST is cacheable” or “POST is never cacheable.” A qualifying response may be eligible to serve a later retrieval. The unsafe POST itself still must be forwarded, and its non-error response triggers target-URI invalidation in traversed caches. The standards neither require an otherwise eligible response to be stored nor establish global freshness after a write.
For a deployed system, verify the actual cache path, response headers, storage behavior, reuse method, and per-hop evidence in an authorized test. Do not infer behavior from the RFC permission alone or treat invalidation in one traversed cache as a purge everywhere.
Primary source register
- RFC 9110 §9.3.3 — POST: explicit freshness, same-target
Content-Location, later GET/HEAD reuse, not POST. - RFC 9110 §8.7 — Content-Location: representation metadata and its relationship to the target resource.
- RFC 9110 §9.2.1 — Safe Methods: safe-method semantics; POST is potentially unsafe.
- RFC 9111 §2 — Overview of Cache Operation: caching is optional; requirements do not mandate that a cache always store and reuse particular responses.
- RFC 9111 §3 — Storing Responses in Caches: general storage constraints.
- RFC 9111 §4 — Constructing Responses from Caches: method/target reuse requirements and unsafe-request write-through.
- RFC 9111 §4.2.1 — Calculating Freshness Lifetime: explicit freshness inputs and their distinction from heuristic freshness.
- RFC 9111 §4.4 — Invalidating Stored Responses: non-error trigger, target-URI invalidation, and non-global scope.
Evidence limits
No authorized target, endpoint, topology, browser, cache, or per-hop capture was supplied. No live test, third-party request, provider, cache library, or analytics was used. The report makes no claim that a particular implementation stores, recognizes, reuses, forwards, or invalidates these requests.