Add max-age=0 to Cache-Control header for Safari compatibility (#1138)

* Initial plan

* Add max-age=0 to Cache-Control header for Safari compatibility

Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: arthurfiorette <47537704+arthurfiorette@users.noreply.github.com>
This commit is contained in:
Copilot 2025-12-08 10:34:37 -03:00 committed by GitHub
parent ce817c7279
commit 9ad2ce4f79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 10 additions and 4 deletions

View File

@ -119,10 +119,16 @@ This option solves this by including predefined headers in the request that inst
Headers included:
- `Cache-Control: no-cache, no-store, must-revalidate`
- `Cache-Control: no-cache, no-store, must-revalidate, max-age=0`
- `Pragma: no-cache`
- `Expires: 0`
::: info Safari Compatibility
The `max-age=0` directive was added to ensure compatibility with Safari (including iOS Safari), which has historically been more aggressive with caching and may not fully respect the `no-cache` directive alone. This combination of headers ensures reliable cache prevention across all major browsers.
:::
::: tip Alternative
While `cacheTakeover` works for most browsers according to [this StackOverflow answer](https://stackoverflow.com/a/2068407), in some rare edge cases it may be unreliable due to browser-specific cache behaviors or network intermediaries.

2
src/cache/cache.ts vendored
View File

@ -66,7 +66,7 @@ export interface CacheProperties<R = unknown, D = unknown> {
*
* Headers included:
*
* - `Cache-Control: no-cache`
* - `Cache-Control: no-cache, no-store, must-revalidate, max-age=0`
* - `Pragma: no-cache`
* - `Expires: 0`
*

View File

@ -101,7 +101,7 @@ export function defaultRequestInterceptor(axios: AxiosCacheInstance): RequestInt
// shouldn't be cached an therefore neither in the browser.
// https://stackoverflow.com/a/2068407
if (config.cache.cacheTakeover) {
config.headers[Header.CacheControl] ??= 'no-cache, no-store, must-revalidate';
config.headers[Header.CacheControl] ??= 'no-cache, no-store, must-revalidate, max-age=0';
config.headers[Header.Pragma] ??= 'no-cache';
config.headers[Header.Expires] ??= '0';
}

View File

@ -366,7 +366,7 @@ describe('Request Interceptor', () => {
const req1 = await axios.get('url');
assert.deepEqual(Object.assign({}, req1.request.config.headers), {
[Header.CacheControl]: 'no-cache, no-store, must-revalidate',
[Header.CacheControl]: 'no-cache, no-store, must-revalidate, max-age=0',
Accept: 'application/json, text/plain, */*',
'Content-Type': undefined,
[Header.Pragma]: 'no-cache',