Куки в Laravel: с чего начать работу с cookie
Как поставить, прочитать и удалить cookie в Laravel: рабочие вызовы, шифрование по умолчанию, привязка к очереди ответа и типичные ошибки новичка. За полчаса от первой куки до понимания, почему она не читается сразу.

К концу этого гайда вы поставите cookie в ответе, прочитаете её из входящего запроса, удалите и разберётесь, почему только что записанная кука не читается на той же странице. Займёт минут двадцать-тридцать, если Laravel уже развёрнут. Всё написано под Laravel 11.x и 12.x; в версиях 9–10 API cookie тот же самый, отличаются только детали конфигурации.
Что нужно иметь до начала
- Установленный Laravel (проверьте:
php artisan --versionпокажет 11.x или 12.x). - PHP 8.2 или выше — требование Laravel 11/12.
- Запущенный локальный сервер:
php artisan serveили Sail/Valet. - Понимание, что такое маршрут и контроллер в Laravel. Модель памяти и внутренности HTTP-стека вам сейчас не нужны.
Отдельно: в Laravel 11 нет файла app/Http/Kernel.php — middleware настраивается в bootstrap/app.php. Это пригодится в разделе про шифрование.
Главное, что нужно понять про куки в Laravel до первой строки кода
Cookie в HTTP — это не переменная, которую вы записали и тут же прочитали. Она уезжает в браузер вместе с ответом сервера, а приходит обратно только со следующим запросом. Поэтому запись и чтение в Laravel разнесены по двум разным местам:
- читаете из объекта запроса —
$request->cookie('name')или фасадCookie::get('name'); - пишете, прикрепляя куку к объекту ответа —
$response->cookie(...)или через очередьCookie::queue(...).
Ещё одна особенность, на которой спотыкаются все: Laravel по умолчанию шифрует все куки через middleware EncryptCookies. Если вы попробуете прочитать куку, поставленную вручную через setcookie() в обход фреймворка, вы получите мусор или null, потому что Laravel ожидает свой формат шифрования.
Кука, записанная в текущем ответе, недоступна в этом же запросе через $request->cookie(). Она станет читаемой только когда браузер вернёт её со следующим обращением. Это не баг — это устройство HTTP.
Шаг 1. Поставить cookie в ответе
Самый прямой способ — прицепить куку к объекту ответа. Создайте маршрут в routes/web.php:
use Illuminate\Support\Facades\Route;
Route::get('/set-cookie', function () {
// response()->cookie(имя, значение, время жизни в минутах)
return response('Кука поставлена')
->cookie('user_theme', 'dark', 60 * 24 * 30); // 30 дней
});
Откройте в браузере /set-cookie. Проверка: во вкладке разработчика (F12 → Application → Cookies в Chrome, или Storage в Firefox) появится кука user_theme. Значение будет выглядеть как длинная зашифрованная строка, а не как dark — это нормально, шифрование включено.
Второй способ — очередь Cookie::queue
Иногда вы хотите поставить куку не там, где формируете ответ, — например, из сервиса или middleware. Тогда добавьте её в очередь, и Laravel прикрепит к финальному ответу автоматически:
use Illuminate\Support\Facades\Cookie;
Route::get('/queue-cookie', function () {
Cookie::queue('last_visit', now()->toDateString(), 60);
return response('Кука в очереди');
});
Проверка: та же вкладка Cookies покажет last_visit. Разница с первым способом только в том, где вы объявляете куку, — результат одинаковый.
Шаг 2. Прочитать cookie из запроса
После того как браузер получил куку, при следующем запросе он пришлёт её обратно. Читаем из объекта запроса:
use Illuminate\Http\Request;
Route::get('/read-cookie', function (Request $request) {
$theme = $request->cookie('user_theme');
// Если куки нет — cookie() вернёт null
return response('Текущая тема: ' . ($theme ?? 'не задана'));
});
Проверка: сначала зайдите на /set-cookie, потом на /read-cookie — увидите «Текущая тема: dark». Если зайдёте на /read-cookie в чистом браузере без установленной куки, получите «не задана».
Тот же результат даёт фасад Cookie::get('user_theme') — он под капотом достаёт значение из текущего запроса.
Шаг 3. Удалить cookie
Удаление — это по сути установка куки с истёкшим сроком жизни. У Laravel для этого есть готовые методы:
use Illuminate\Support\Facades\Cookie;
Route::get('/forget-cookie', function () {
// Способ через очередь
Cookie::queue(Cookie::forget('user_theme'));
return response('Кука удалена');
});
Или через ответ напрямую:
Route::get('/forget-cookie-response', function () {
return response('Удалено')
->withoutCookie('user_theme');
});
Проверка: после захода браузер получит куку user_theme с датой истечения в прошлом и удалит её. Во вкладке Cookies она пропадёт.
Шифрование: почему значение выглядит как мусор
Middleware EncryptCookies шифрует и расшифровывает куки прозрачно: вы работаете с обычными значениями, а в браузере лежит шифртекст. Ключ шифрования — APP_KEY из файла .env. Если ключ сменить, все старые куки перестанут читаться.
Иногда куку нужно оставить нешифрованной — например, её читает фронтенд-скрипт или сторонний сервис. В Laravel 11/12 исключения задаются в bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) {
$middleware->encryptCookies(except: [
'user_theme', // эта кука останется в открытом виде
]);
})
После этого user_theme в браузере будет читаться как dark, а не как шифртекст. Точный синтаксис метода сверяйте в актуальной документации по middleware вашей версии — в ветках 9–10 исключения задавались свойством $except внутри самого класса middleware.
Куки, которые ставит сам Laravel
Не удивляйтесь двум служебным кукам, которые появятся сами по себе на любом маршруте группы web:
XSRF-TOKEN— токен для защиты от CSRF*. Его читает JavaScript при AJAX-запросах.- кука сессии (имя задаётся в
config/session.php, по умолчанию собирается из имени приложения) — идентификатор сессии пользователя.
* CSRF (Cross-Site Request Forgery) — атака, когда чужой сайт отправляет запрос от имени залогиненного пользователя. Токен подтверждает, что запрос пришёл с вашей формы, а не со стороны.
Способы записи и чтения рядом
| Задача | Через фасад Cookie | Через request/response |
|---|---|---|
| Поставить | Cookie::queue('n', 'v', 60) | response()->cookie('n', 'v', 60) |
| Прочитать | Cookie::get('n') | $request->cookie('n') |
| Удалить | Cookie::queue(Cookie::forget('n')) | response()->withoutCookie('n') |
Фасад удобен, когда вы не контролируете финальный ответ (middleware, сервисы). Методы request/response нагляднее в контроллере, где ответ у вас на руках.
Если не получилось
- Кука не появляется в браузере. Проверьте, что вы возвращаете объект ответа с кукой из маршрута, а не просто вызываете
response()->cookie()и отбрасываете результат. Прикреплённая, но не возвращённая кука никуда не уедет. - Значение куки — набор случайных символов. Это шифрование по умолчанию, а не ошибка. Хотите открытый вид — добавьте имя куки в исключения
encryptCookies. $request->cookie()возвращает null сразу после установки. Так и должно быть: кука станет доступна только на следующем запросе. Проверяйте на отдельном маршруте после первого визита.- Кука с фронтенда (поставленная через JS) не читается в Laravel. Она не зашифрована форматом Laravel. Либо добавьте её в исключения шифрования, либо читайте вручную из
$_COOKIE, понимая риски. - Кука не сохраняется между поддоменами или в HTTPS. Смотрите параметры
domain,secureиsame_siteвconfig/session.php— они влияют и на служебные куки, и на ваши, если вы задаёте те же атрибуты.
Что дальше
Первый рабочий цикл поставить–прочитать–удалить у вас есть. Дальше стоит настроить атрибуты куки под ваш случай: SameSite, Secure, HttpOnly и время жизни — методы cookie() и queue() принимают эти параметры дополнительными аргументами, точный порядок смотрите в документации по классу Illuminate\Cookie\CookieJar. Если храните в куках что-то чувствительнее темы оформления, посмотрите в сторону сессий Laravel: они безопаснее, потому что данные лежат на сервере, а в браузере только идентификатор.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: Laravel — HTTP Requests: Cookies (официальная документация), Laravel — HTTP Responses: Attaching Cookies (официальная документация)
Частые вопросы
Почему кука, которую я только что поставил, не читается на той же странице?
А если у меня Laravel 10 или 9 — этот код сработает?
Значение куки в браузере выглядит как длинная случайная строка — это ошибка?
Как поставить куку без шифрования, чтобы её читал JavaScript?
Что будет с существующими куками, если я сменю APP_KEY?
Cookie::queue() или response()->cookie() — что выбрать?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.