From 6f297069ed07b25c540504a1775bf47a9ba0dea5 Mon Sep 17 00:00:00 2001 From: Frazer Smith Date: Fri, 27 Feb 2026 13:55:17 +0000 Subject: [PATCH] fix(index): add `proxy-revalidate` directive to cache-control --- README.md | 4 ++-- src/index.js | 2 +- test/index.test.js | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d9ba008..cf7fb9f 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Inspired by [nocache](https://github.com/helmetjs/nocache), the `fastify-disablecache` plugin sets the following response headers and values to disable client-side caching: ``` -Cache-Control: no-store, max-age=0, must-revalidate +Cache-Control: no-store, max-age=0, must-revalidate, proxy-revalidate Expires: 0 Pragma: no-cache Surrogate-Control: no-store @@ -23,7 +23,7 @@ This plugin was created out of a need for an easy way to disable client-side cac ### Why these headers? -- `Cache-Control` - Primary response header for configuring cache controls [since HTTP/1.1](https://httpwg.org/specs/rfc7234.html#header.cache-control); whilst `no-store` is the directive to disable caching, clients such as [Internet Explorer](https://learn.microsoft.com/en-us/troubleshoot/developer/browsers/connectivity-navigation/how-to-prevent-caching#the-cache-control-header) did not use it, thus the addition of `max-age=0, must-revalidate` +- `Cache-Control` - Primary response header for configuring cache controls [since HTTP/1.1](https://httpwg.org/specs/rfc7234.html#header.cache-control); whilst `no-store` is the directive to disable caching, clients such as [Internet Explorer](https://learn.microsoft.com/en-us/troubleshoot/developer/browsers/connectivity-navigation/how-to-prevent-caching#the-cache-control-header) did not use it, thus the addition of `max-age=0, must-revalidate`; `proxy-revalidate` is added to ensure legacy proxies that only partially implemented support for `must-revalidate` also revalidate the response - `Expires` - Included for backwards compatibility with [HTTP/1.0 caches](https://w3.org/Protocols/HTTP/1.0/spec.html#Expires) - `Pragma` - Included for backwards compatibility with [HTTP/1.0 caches](https://w3.org/Protocols/HTTP/1.0/spec.html#Pragma), is [used by Internet Explorer](https://docs.microsoft.com/en-us/troubleshoot/developer/browsers/connectivity-navigation/how-to-prevent-caching#the-pragma-no-cache-header) - `Surrogate-Control` - Not a standardised response header but is [used by CDNs and reverse proxies](https://w3.org/TR/edge-arch/) for cache control diff --git a/src/index.js b/src/index.js index ef6269a..f05cb57 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ const fp = require("fastify-plugin"); /** @type {Readonly>} */ const CACHE_HEADERS = Object.freeze({ - "cache-control": "no-store, max-age=0, must-revalidate", + "cache-control": "no-store, max-age=0, must-revalidate, proxy-revalidate", expires: "0", pragma: "no-cache", "surrogate-control": "no-store", diff --git a/test/index.test.js b/test/index.test.js index 9abb797..2dc8375 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -12,8 +12,8 @@ const plugin = require("../src"); * @author Frazer Smith * @description Check if an object contains a subset of properties. * @todo Replace with `assert.partialDeepStrictEqual` when available. - * @param {Record} actual - The actual object. - * @param {Record} expected - The expected subset of properties. + * @param {Record} actual - The actual object. + * @param {Record} expected - The expected subset of properties. */ function matchObject(actual, expected) { for (const [key, value] of Object.entries(expected)) { @@ -52,7 +52,8 @@ describe("Disablecache plugin", () => { t.plan(2); t.assert.strictEqual(response.body, "ok"); matchObject(response.headers, { - "cache-control": "no-store, max-age=0, must-revalidate", + "cache-control": + "no-store, max-age=0, must-revalidate, proxy-revalidate", expires: "0", pragma: "no-cache", "surrogate-control": "no-store",