Как можно запретить кэшировать HTTP запрос в браузере?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отключение кэширования HTTP запросов
Браузер кэширует HTTP запросы по умолчанию на основе Cache-Control заголовков. Иногда нужно отключить кэширование для конкретных запросов. Расскажу все варианты.
На стороне бэкенда (правильный способ)
Бэкенд должен установить соответствующие HTTP заголовки:
Cache-Control: no-cache, no-store, max-age=0
Pragma: no-cache
Expires: 0
Примеры для разных языков:
# Python Flask
@app.route('/api/users')
def get_users():
response = make_response(jsonify(users))
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '0'
return response
// Node.js Express
app.get('/api/users', (req, res) => {
res.set('Cache-Control', 'no-cache, no-store, max-age=0');
res.set('Pragma', 'no-cache');
res.set('Expires', '0');
res.json(users);
});
// C# .NET
public IActionResult GetUsers()
{
Response.Headers.CacheControl = "no-cache, no-store, max-age=0";
Response.Headers.Pragma = "no-cache";
Response.Headers.Expires = "0";
return Ok(users);
}
Понимание Cache-Control директив
| Директива | Значение |
|---|---|
no-cache | Браузер должен проверить с сервером перед использованием кешированной версии |
no-store | Не кешировать вообще (запрос и ответ) |
max-age=0 | Кеш истекает сразу (0 секунд) |
must-revalidate | Кеш можно использовать но проверить на свежесть |
private | Кеш только для браузера (не прокси) |
public | Кеш для браузера и прокси |
На стороне фронтенда (если бэкенд не помогает)
Вариант 1: Добавить query параметр с меняющимся значением
// Браузер видит разные URL как разные запросы
const timestamp = Date.now();
fetch(`/api/users?t=${timestamp}`)
.then(r => r.json())
.then(data => console.log(data));
Примеры параметров:
// С временем
`/api/users?t=${Date.now()}`
// С UUID
import { v4 as uuid } from 'uuid';
`/api/users?v=${uuid()}`
// С версией (не рекомендуется)
`/api/users?v=${appVersion}`
Вариант 2: Установить заголовки в fetch запросе
fetch('/api/users', {
method: 'GET',
headers: {
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
})
.then(r => r.json())
.then(data => console.log(data));
Важно: Браузер НЕ уважает Cache-Control заголовок в request'е. Это работает только если бэкенд поддерживает.
Вариант 3: Использовать fetch() с cache опцией
// Не использовать кеш при загрузке
fetch('/api/users', {
cache: 'no-store' // Или 'no-cache', 'reload'
})
.then(r => r.json())
.then(data => console.log(data));
Доступные значения для cache:
// default - использовать кеш если доступен
fetch('/api/data', { cache: 'default' });
// no-store - всегда запрашивать с сервера
fetch('/api/data', { cache: 'no-store' });
// no-cache - проверить с сервером перед использованием
fetch('/api/data', { cache: 'no-cache' });
// reload - игнорировать кеш и переагрузить
fetch('/api/data', { cache: 'reload' });
// only-if-cached - только из кеша (не запрашивать)
fetch('/api/data', { cache: 'only-if-cached' });
Практические примеры
Для API запросов (всегда свежие данные)
const api = {
get: (url) => fetch(url, { cache: 'no-store' }).then(r => r.json()),
post: (url, body) => fetch(url, {
method: 'POST',
body: JSON.stringify(body),
cache: 'no-store'
}).then(r => r.json())
};
// Использование
await api.get('/api/users');
await api.post('/api/users', { name: 'John' });
С debouncing и повторными попытками
const fetchWithoutCache = (url, options = {}) => {
return fetch(url, {
...options,
cache: 'no-store',
headers: {
...options.headers,
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
}
});
};
// Использование
await fetchWithoutCache('/api/data');
React Hook для свежих данных
import { useState, useEffect, useCallback } from 'react';
function useFreshData(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
setLoading(true);
try {
const response = await fetch(url, { cache: 'no-store' });
if (!response.ok) throw new Error('Failed to fetch');
const json = await response.json();
setData(json);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, [url]);
useEffect(() => {
fetchData();
}, [fetchData]);
return { data, loading, error, refetch: fetchData };
}
// Использование
function UserList() {
const { data: users, loading } = useFreshData('/api/users');
// ...
}
Для изображений
Изображения кэшируются отдельно:
<!-- Добавить query параметр -->
<img src="/images/logo.png?t=12345" alt="Logo" />
<!-- Или в JavaScript -->
<img src={`/images/logo.png?t=${Date.now()}`} alt="Logo" />
Для стилей и скриптов
<!-- Стили -->
<link rel="stylesheet" href="/styles.css?v=1.2.3" />
<!-- Скрипты -->
<script src="/app.js?v=1.2.3"></script>
Лучше использовать версионирование (v=1.2.3) чем временные метки потому что версия не меняется каждый запрос.
Service Worker для контроля кеша
Для более сложного управления кешем:
// service-worker.js
self.addEventListener('fetch', event => {
// Для API запросов - всегда с сервера
if (event.request.url.includes('/api/')) {
event.respondWith(fetch(event.request));
}
// Для статики - кеш с fallback
else {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
}
});
Проверка в DevTools
- Открыть Network tab
- Посмотреть заголовки ответа сервера
- Проверить строку "Cache-Control"
Шпаргалка
// ПРАВИЛЬНО: Попросить бэкенд отключить кеш
// На стороне сервера установить заголовки
// ХОРОШО: Использовать cache опцию fetch
fetch('/api/data', { cache: 'no-store' });
// ВРЕМЕННОЕ РЕШЕНИЕ: Добавить query параметр
fetch(`/api/data?t=${Date.now()}`);
// НЕ РАБОТАЕТ: Установить Cache-Control в request
// (Браузер просто игнорирует)
fetch('/api/data', {
headers: { 'Cache-Control': 'no-cache' } // Не поможет!
});
Best Practice
- Координируй с бэкендом — установи правильные заголовки на сервере
- Используй версионирование для статики —
/app-v1.2.3.jsвместо/app.js?t=... - API запросы часто не должны кэшироваться — используй
cache: 'no-store' - Для критичных данных — обновляй периодически через polling или WebSocket
- Service Worker — для более сложного контроля кеширования
Отключение кэша снижает производительность поэтому используй его только когда действительно нужны свежие данные.