Изначально работать с HTTP было не очень просто. Дело в том, что это протокол без сохранения состояния, то есть каждый запрос-ответ не связан с предыдущим запросом-ответом. Это было неудобно, потому что иногда нам приходится запоминать информацию: например об аутентификации пользователя или о товарах в его корзине в интернет-магазине.
Тут возникает проблема: «Как запомнить, что это тот пользователь, с которым мы только что работали?». Решение этой проблемы было найдено когда был придуман механизм, который называется Cookie.
В этом уроке мы разберемся, что такое куки и как они работают.
Как работают куки
Давайте сделаем запрос к сервису HTTP Server и посмотрим, как этот механизм работает
Выполним запрос для получения только заголовков, для этого добавим к запуску curl флаг --head:
curl --head https://http.hexlet.app/http-protocol/example
HTTP/2 200
date: Wed, 02 Oct 2024 15:05:59 GMT
content-type: text/html; charset=ISO-8859-1
accept-ranges: none
cache-control: private, max-age=0
expires: -1
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
set-cookie: 1P_JAR=2020-01-18-09; expires=Mon, 17-Feb-2020 09:24:50 GMT; path=/; domain=.hexlet.app; Secure
set-cookie: NID=196=wsHLMAMfnAaSyF7zduokI8TJeE5UoIKPHYC58HYH93VMnev9Nc2bAjhRdzoc4UhmuOd7ZVCorDnzGDe51yPefsRMeVyOFnYdHYYgQNqI8A1dYuk4pDK4OJurQgL4lX8kiNGSNi_kkUESFQ-MqLCB_YspxA9JRejhZdkTRtGyHNk; expires=Sun, 19-Jul-2020 09:24:50 GMT; path=/; domain=.hexlet.app; HttpOnly
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-xss-protection: 0
cf-cache-status: DYNAMIC
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=9ileixnwWqNV5AorloHI%2FKLp9Kw17SfIpzJK9XGAj2QNpomfZ4iNA0qmZojD7NuKahGwh43YcZ83hgmFRRCcQ9tubJWyGvtw14R4WKJRDWcMIqzn8meMSbRYAI6S0q2UXv0%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
speculation-rules: "/cdn-cgi/speculation"
server: cloudflare
cf-ray: 8cc597ff1f6c0ebd-HKG
Мы видим два заголовка, которые занимаются установкой cookie — set-cookie. Обратите внимание, что каждая cookie посылается в отдельном заголовке. Таких заголовков может быть достаточно много.
Изнутри кука представляет собой пару ключ=значение и отделяется от дополнительных параметров точкой с запятой. Куки сохраняются в браузере на клиенте и при следующем запросе он отправляет их обратно на сервер. Непосредственно в браузере они никак не используются.
Хорошая аналогия — это как получить номерок в гардеробе и потом вернуть его, чтобы понять какая куртка ваша. При этом сам номерок никакой ценности не представляет, и его нельзя использовать самостоятельно.
Куки делятся как минимум на два типа: сессионные и постоянные.
Сессионные куки
Сессионные куки в нашем запросе не устанавливаются, так как мы видим дополнительные параметры в заголовке set-cookie. Если бы их не было, то кука называлась бы сессионной. Основное их отличие от постоянных в том, что такая кука удаляется при закрытии браузера. Наглядный пример — это механизм работы галочки «запомнить меня». Если вы авторизуетесь и не отметите эту галочку, а потом закроете браузер и снова зайдете на сайт, то будете не авторизованы. Так происходит потому, что используется сессионная кука.
Постоянные куки
Вернемся к запросу выше. В этом случае устанавливаются постоянные куки. Они сохраняются на жестком диске — место их хранения может быть разным в зависимости от браузера. Такие куки отличаются от сессионных тем, что можно управлять длиной их жизни при помощи параметра expires:
expires=Thu, 16-Jul-2020 03:39:50 GMT;
В параметре expires указывается дата удаления куки, после которой она не будет отсылаться на сервер. Стоит сказать, что есть еще один параметр, который используется для тех же целей — MAX-AGE. В его значении указывается количество секунд, по истечении которых кука будет удалена:
MAX-AGE=2592000;
Так как часть браузеров не поддерживают MAX-AGE, некоторые фреймворки часто устанавливают сразу оба параметра и браузеры просто игнорируют тот, который им не нужен. Таким образом заголовок set-cookie, который содержит два параметра MAX-AGE и expires, считается валидным. В стандарте также говорится, что регистр имени куки не имеет значения.
Параметры domain и path
Также можно установить еще несколько параметров. Параметры domain и path задают область видимости куки — это URL, на которые кука может отправляться. Если они не заданы, то по умолчанию кука будет пересылаться на сервер только для текущего пути и домена. В нашем примере в path указан корень сайта, то есть кука будет отправляться для всех страниц:
domain=.hexlet.app; path=/;
Обратите внимание на одну важную деталь в этом примере. Если установлен domain=.hexlet.app, то кука будет работать не только для всех страниц сайта, но и для всех поддоменов — при этом наличие точки перед именем домена не имеет значения. Если мы совсем не установим параметр domain, то кука для поддоменов работать не будет, хотя по умолчанию значение домена будет hexlet.app.
Уникальность куки определяется тремя параметрами key (имя куки), domain и path. Это значит, что если какую-то куку нужно переустановить, то при следующем запросе в set-cookie эти параметры должны совпадать. Если хотя бы один из них отличается, то будет установлена новая кука.
Удаление куки
Заголовка для удаления куки не существует. Чтобы удалить ее, нужно установить нулевой или отрицательный MAX-AGE, либо задать expires в прошлом, тогда кука будет немедленно удалена.
HttpOnly cookie
Можно заметить, что в нашем примере установлен дополнительный параметр HttpOnly. HttpOnly-куки передаются с AJAX-запросами, но их нельзя получить через JavaScript на странице сайта. Это дополнительный уровень безопасности от XSS-атак.
Отправка на сервер
Мы обновляем страницу в браузере. После этого происходит отправка следующего заголовка:
Cookie: GCLB=CLiC7uWajOOrzAE;_hexlet_session2=gu3n8MCidqZ28VfjpzJuF74d4ohla6uYq9Q%2B2XBcalsa3VUCzURBWTXvscuzSI%2BF3lnHAN%2FUt6IJnXgkH%2B6jDKgyStVb8W%2BLHwIbypoxajN3fB5ksFT3Qu28RvDQpL6hBmqq7V2eFdfLMGtkmtcpfAUYNGffwaBAlQyQKnvhkCpEf5IIWkwWfe9Nt8dG3lIueeir9fGxZP7Fpcw9IP9HfgSansgXugtFI1rw06UhgrrK%2BEnaf4EmIgVdH6KYpDBKXpUUXz8vFRvkOMX5j%2BZNMTu%2BKDBzmGlFjcm1mCZl4ozZWDCocFO4CTW7z9LmzKYbcEGkUEhRbOu%2BTvLgVo80LilK--x3y6jxx%2FjYcLp5tr--9nrQ0XmAhtGAuIFvMYvWig%3D%3D
Все куки отправляются одним заголовком в формате key=value; key=value без дополнительных параметров.
Дополнительные материалы
- HTTP Cookie / Mozilla
- HTTP Куки / Википедия
- RFC 6265: стандарт, описывающий cookie
- Local Storage vs. Session Storage vs. Cookie
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.