Современный подход к работе с куки

Kate

Administrator
Команда форума
Вы когда-нибудь работали с куки? Казалось ли вам при этом, что их использование организовано просто и понятно? Полагаю, что в работе с куки есть множество нюансов, о которых стоит знать новичкам.


Свойство document.cookie​


Взглянем на классический способ работы с куки. Соответствующая спецификация существует, благодаря Netscape, с 1994 года. Компания Netscape реализовала свойство document.cookie в Netscape Navigator в 1996 году. Вот определение куки из тех времён:

Куки — это небольшой фрагмент информации, хранящийся на клиентской машине в файле cookies.txt.

Главу про document.cookie даже можно найти во втором издании книги «Javascript. The Definitive Guide», которое вышло в январе 1997 года. Это было 24 года тому назад. И мы всё ещё пользуемся тем же старым способом работы с куки ради обратной совместимости.

Как же это выглядит?

Получение куки​


const cookies = document.cookie;
// возвращает "_octo=GH1.1.123.456; tz=Europe%2FMinsk" on GitHub


Да, именно так всё и делается. В нашем распоряжении оказывается строка со всеми значениями, хранящимися в куки-файле, разделёнными точкой с запятой.

Как вытащить из этой строки отдельное значение? Если вам кажется, что для этого надо самостоятельно разбить строку на части — знайте, что так оно и есть:

function getCookieValue(name) {
const cookies = document.cookie.split(';');
const res = cookies.find(c => c.startsWith(name + '='));
if (res) {
return res.substring(res.indexOf('=') + 1);
}
}


Как узнать о том, когда истекает срок действия какого-нибудь из куки? Да, в общем-то, никак.

А как узнать домен, с которого установлен какой-нибудь куки? Тоже никак.

Правда, если надо, можно распарсить HTTP-заголовок Cookie.

Установка куки​


document.cookie = 'theme=dark';


Вышеприведённая команда позволяет создать куки с именем theme, значением которого является dark. Хорошо. Значит ли это, что document.cookie — это строка. Нет, не значит. Это — сеттер.

document.cookie = 'mozilla=netscape';


Эта команда не перезапишет куки с именем theme. Она создаст новый куки с именем mozilla. Теперь у нас имеются два куки.

По умолчанию срок действия куки, созданного так, как показано выше, истекает после закрытия браузера. Но при создании куки можно указать срок его действия:

document.cookie = 'browser=ie11; expires=Tue, 17 Aug 2021 00:00:00 GMT';


Да. Это — как раз то, что мне нужно — подбирать дату и время истечения срока действия куки в формате GMT каждый раз, когда нужно установить куки. Ладно, давайте воспользуемся для решения этой задачи JavaScript-кодом:

const date = new Date();
date.setTime(date.getTime() + (30 * 24 * 60 * 60 * 1000)); // здорово-то как
document.cookie = `login=mefody; expires=${date.toUTCString()}; path=/`;


Но, к счастью, у нас есть и другой способ установки момента истечения срока действия куки:

document.cookie = 'element=caesium; max-age=952001689';


Свойство max-age представляет собой срок «жизни» куки в секундах. Соответствующее значение имеет более высокий приоритет, чем то, которое задано с помощью свойства expires.

И не надо забывать о свойствах path и domain. По умолчанию куки устанавливаются для текущего расположения и текущего хоста. Если надо установить куки для всего домена — надо будет добавить к команде установки куки конструкцию такого вида:

; path=/; domain=example.com


Удаление куки​


document.cookie = 'login=; expires=Thu, 01 Jan 1970 00:00:00 GMT';


Для удаления куки надо установить дату и время истечения срока действия куки на какой-нибудь момент из прошлого. Для того чтобы всё точно сработало бы — тут рекомендуется использовать начало эпохи Unix.

Работа с куки в сервис-воркерах​


Это просто невозможно. Дело в том, что работа с document.cookie — это синхронная операция, в результате воспользоваться ей в сервис-воркере нельзя.

Cookie Store API​


Существует черновик стандарта одного замечательно API, направленного на работу с куки, который способен значительно облегчить нам жизнь в будущем.

Во-первых — это асинхронный API, а значит — пользоваться им можно, не блокируя главный поток. Применять его можно и в сервис-воркерах.

Во-вторых — этот API устроен гораздо понятнее, чем существующий механизм работы с куки.

▍Получение куки​


const cookies = await cookieStore.getAll();
const sessionCookies = await cookieStore.getAll({
name: 'session_',
matchType: 'starts-with',
});


Метод getAll возвращает массив, а не строку. Именно этого я и жду, когда пытаюсь получить некий список.

const ga = await cookieStore.get('_ga');
/**
{
"domain": "mozilla.org",
"expires": 1682945254000,
"name": "_ga",
"path": "/",
"sameSite": "lax",
"secure": false,
"value": "GA1.2.891784426.1616320570"
}
*/


А вот — приятная неожиданность. Можно узнать и дату истечения срока действия куки, и сведения о домене и пути, и при этом не пользоваться никакими хаками.

▍Установка куки​


await cookieStore.set('name', 'value');


Или так:

await cookieStore.set({
name: 'name',
value: 'value',
expires: Date.now() + 86400,
domain: self.location.host,
path: '/',
secure: self.location.protocol === 'https:',
httpOnly: false,
});


Мне очень нравится этот синтаксис!

▍Удаление куки​


await cookieStore.delete('ie6');


Или можно, как раньше, установить дату истечения срока действия куки на некий момент в прошлом, но не вижу причины поступать именно так.

▍События куки​


cookieStore.addEventListener('change', (event) => {
for (const cookie in event.changed) {
console.log(`Cookie ${cookie.name} changed to ${cookie.value}`);
}
});


Как видите, теперь у нас есть возможность подписываться на изменения куки, не занимаясь опросом document.cookie, блокирующим главный поток. Фантастика!

▍Сервис-воркеры​


// service-worker.js

await self.registration.cookies.subscribe([
{
name: 'cookie-name',
url: '/path-to-track',
}
]);

self.addEventListener('cookiechange', (event) => {
// обработка изменений
});


Можно ли пользоваться этим API прямо сейчас?​


Хотя этим API уже можно пользоваться, но тут надо проявлять осторожность. Cookie Store API работоспособно в Chrome 87+ (Edge 87+, Opera 73+). В других браузерах можно воспользоваться полифиллом, который, правда, не возвращает полной информации о куки, как это сделано в настоящем API. Прогрессивные улучшения — это вещь.

И учитывайте, что спецификация этого API всё ещё находится в статусе «Draft Community Group Report». Но если в вашем проекте важен хороший «опыт разработчика» — попробуйте современный способ работы с куки.


Источник статьи: https://habr.com/ru/company/ruvds/blog/556742/
 
Сверху