Для чтения и записи cookie используется свойство document.cookie. Однако, оно представляет собой не объект, а строку в специальном формате, для удобной манипуляций с которой нужны дополнительные функции.
[cut]
Наверняка у вас есть cookie, которые привязаны к этому сайту. Давайте полюбуемся на них. Вот так:
//+ run
alert( document.cookie );Эта строка состоит из пар ключ=значение, которые перечисляются через точку с запятой с пробелом "; ".
Значит, чтобы прочитать cookie, достаточно разбить строку по "; ", и затем найти нужный ключ. Это можно делать либо через split и работу с массивом, либо через регулярное выражение.
Следующая функция getCookie(name) возвращает cookie с именем name:
// возвращает cookie с именем name, если есть, если нет, то undefined
function getCookie(name) {
var matches = document.cookie.match(new RegExp(
"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
));
return matches ? decodeURIComponent(matches[1]) : undefined;
}Обратим внимание, что значение может быть любым. Если оно содержит символы, нарушающие форматирование, например, пробелы или ;, то оно кодируется при помощи encodeURIComponent. Функция getCookie автоматически раскодирует его.
В document.cookie можно писать. При этом запись не перезаписывает существующие cookie, а дополняет к ним!
Например, такая строка поставит cookie с именем userName и значением Vasya:
//+ run
document.cookie = "userName=Vasya";...Однако, всё не так просто. У cookie есть ряд важных настроек, которые очень желательно указать, так как значения по умолчанию у них неудобны.
Эти настройки указываются после пары ключ=значение, каждое -- после точки с запятой:
- `path=/mypath`
- Путь, внутри которого будет доступ к cookie. Если не указать, то имеется в виду текущий путь и все пути ниже него.
Как правило, используется
path=/, то есть cookie доступно со всех страниц сайта. - `domain=site.com`
- Домен, на котором доступно cookie. Если не указать, то текущий домен. Допустимо указывать текущий домен `site.com` и его поддомены, например `forum.site.com`.
Если указать специальную маску
.site.com, то cookie будет доступно на сайте и всех его поддоменах. Это используется, например, в случаях, когда кука содержит данные авторизации и должна быть доступна как наsite.com, так и наforum.site.com. - `expires=Tue, 19 Jan 2038 03:14:07 GMT`
- Дата истечения куки в формате GMT. Получить нужную дату можно, используя объект `Date`. Его можно установить в любое время, а потом вызвать `toUTCString()`, например:
// +1 день от текущего момента var date = new Date; date.setDate(date.getDate() + 1); alert( date.toUTCString() );
Если дату не указать, то cookie будет считаться "сессионным". Такое cookie удаляется при закрытии браузера. Если дата в прошлом, то кука будет удалена.
- `secure`
- Cookie можно передавать только по HTTPS.
Например, чтобы поставить cookie name=value по текущему пути с датой истечения через 60 секунд:
//+ run
var date = new Date(new Date().getTime() + 60 * 1000);
document.cookie = "name=value; path=/; expires=" + date.toUTCString();Чтобы удалить это cookie:
//+ run
var date = new Date(0);
document.cookie = "name=; path=/; expires=" + date.toUTCString();При удалении значение не важно. Можно его не указывать, как сделано в коде выше.
Если собрать все настройки воедино, вот такая функция ставит куки:
function setCookie(name, value, options) {
options = options || {};
var expires = options.expires;
if (typeof expires == "number" && expires) {
var d = new Date();
d.setTime(d.getTime() + expires * 1000);
expires = options.expires = d;
}
if (expires && expires.toUTCString) {
options.expires = expires.toUTCString();
}
value = encodeURIComponent(value);
var updatedCookie = name + "=" + value;
for (var propName in options) {
updatedCookie += "; " + propName;
var propValue = options[propName];
if (propValue !== true) {
updatedCookie += "=" + propValue;
}
}
document.cookie = updatedCookie;
}Аргументы:
- name
- название cookie
- value
- значение cookie (строка)
- options
-
Объект с дополнительными свойствами для установки cookie:
- expires
- Время истечения cookie. Интерпретируется по-разному, в зависимости от типа:
- Число -- количество секунд до истечения. Например, `expires: 3600` -- кука на час.
- Объект типа [Date](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Date) -- дата истечения.
- Если expires в прошлом, то cookie будет удалено.
- Если expires отсутствует или `0`, то cookie будет установлено как сессионное и исчезнет при закрытии браузера.
- path
- Путь для cookie.
- domain
- Домен для cookie.
- secure
- Если `true`, то пересылать cookie только по защищенному соединению.
Здесь всё просто -- удаляем вызовом setCookie с датой в прошлом.
function deleteCookie(name) {
setCookie(name, "", {
expires: -1
})
}При работе с cookie есть важная тонкость, которая касается внешних ресурсов.
Теоретически, любой ресурс, который загружает браузер, может поставить cookie.
Например:
- Если на странице есть `
`, то вместе с картинкой в ответ сервер может прислать заголовки, устанавливающие cookie.
- Если на странице есть `<iframe src="http://facebook.com/button.php">`, то во-первых сервер может вместе с `button.php` прислать cookie, а во-вторых JS-код внутри ифрейма может записать в `document.cookie`
При этом cookie будут принадлежать тому домену, который их поставил. То есть, на mail.ru для первого случая, и на facebook.com во втором.
Такие cookie, которые не принадлежат основной странице, называются "сторонними" (3rd party) cookies. Не все браузеры их разрешают.
Как правило, в настройках браузера можно поставить "Блокировать данные и файлы cookie сторонних сайтов" (Chrome).
В Safari такая настройка включена по умолчанию и выглядит так:
Цель этого запрета -- защитить посетителей от слежки со стороны рекламодателей, которые вместе с картинкой-баннером присылают и куки, таким образом помечая посетителей.
Например, на многих сайтах стоят баннеры и другая реклама Google Ads. При помощи таких cookie компания Google будет знать, какие именно сайты вы посещаете, сколько времени вы на них проводите и многое другое.
Как? Да очень просто -- на каждом сайте загружается, к примеру, картинка с рекламой. При этом баннер берётся с домена, принадлежащего Google. Вместе с баннером Google ставит cookie со специальным уникальным идентификатором.
Далее, при следующем запросе на баннер, браузер пошлёт стандартные заголовки, которые включают в себя:
- Cookie с домена баннера, то есть уникальный идентификатор, который был поставлен ранее.
- Стандартный заголовок Referrer (его не будет при HTTPS!), который говорит, с какого сайта сделан запрос. Да, впрочем, Google и так знает, с какого сайта запрос, ведь идентификатор сайта есть в URL.
Так что Google может хранить в своей базе, какие именно сайты из тех, на которых есть баннер Google, вы посещали, когда вы на них были, и т.п. Этот идентификатор легко привязывается к остальной информации от других сервисов, и таким образом картина слежки получается довольно-таки глобальной.
Здесь я не утверждаю, что в конкретной компании Google всё именно так... Но во-первых, сделать так легко, во-вторых идентификаторы действительно ставятся, а в-третьих, такие знания о человеке позволяют решать, какую именно рекламу и когда ему показать. А это основная доля доходов Google, благодаря которой корпорация существует.
Возможно, компания Apple, которая выпустила Safari, поставила такой флаг по умолчанию именно для уменьшения влияния Google?
Итак, Safari запрещает сторонние cookie по умолчанию. Другие браузеры предоставляют такую возможность, если посетитель захочет.
А что, если ну очень надо поставить стороннюю cookie, и чтобы это было надёжно?
Такая задача действительно возникает, например, в системе кросс-доменной авторизации, когда есть несколько доменов 2-го уровня, и хочется, чтобы посетитель, который входит в один сайт, автоматически распознавался во всей сетке. При этом cookie для авторизации ставятся на главный домен -- "мастер", а остальные сайты запрашивают их при помощи специального скрипта (и, как правило, копируют к себе для оптимизации, но здесь это не суть).
Ещё пример -- когда есть внешний виджет, например, iframe с информационным сервисом, который можно подключать на разные сайты. И этот iframe должен знать что-то о посетителе, опять же, авторизация или какие-то настройки, которые хорошо бы хранить в cookie.
Есть несколько способов поставить 3rd-party cookie для Safari.
- Использовать ифрейм.
- Ифрейм является полноценным окном браузера. В нём должна быть доступна вся функциональность, в том числе cookie. Как браузер решает, что ифрейм "сторонний" и нужно запретить для него и его скриптов установку cookie? Критерий таков: "в ифрейме нет навигации". Если навигация есть, то ифрейм признаётся полноценным окном.
Например, в сторонний
iframeможно сделать POST. И тогда, в ответ на POST, сервер может поставить cookie. Или прислать документ, который это делает. Ифрейм, в который прошёл POST, считается родным и надёжным. - Popup-окно
- Другой вариант -- использовать popup, то есть при помощи `window.open` открывать именно окно со стороннего домена, и уже там ставить cookie. Это тоже работает.
- Редирект
- Ещё одно альтернативное решение, которое подходит не везде - это сделать интеграцию со сторонним доменом, такую что на него можно сделать редирект, он ставит cookie и делает редирект обратно.
- На Cookie наложены ограничения:
- Имя и значение (после `encodeURIComponent`) вместе не должны превышать 4кб.
- Общее количество cookie на домен ограничено 30-50, в зависимости от браузера.
- Разные домены 2го уровня полностью изолированы. Но в пределах доменов 3го уровня куки можно ставить свободно с указанием `domain`.
- Сервер может поставить cookie с дополнительным флагом `HttpOnly`. Cookie с таким параметром передаётся только в заголовках, оно никак не доступно из JavaScript.
- Иногда посетители отключают cookie. Отловить это можно проверкой свойства [navigator.cookieEnabled](https://developer.mozilla.org/en-US/docs/DOM/window.navigator.cookieEnabled)
//+ run if (!navigator.cookieEnabled) { alert( 'Включите cookie для комфортной работы с этим сайтом' ); }
...Конечно, предполагается, что включён JavaScript. Впрочем, посетитель без JS и cookie с большой вероятностью не человек, а бот.
Файл с функциями для работы с cookie: cookie.js.

