Cookies
Ciasteczka to małe kawałki tekstu przechowywane przez przeglądarkę, a które najczęściej służą zarówno do zapisywania krótkich informacji takich jak np. id użytkownika, numer aktualnej sesji, preferowany typ reklam itp., ale równocześnie też do przesyłania takich danych między serwerem a przeglądarką, dzięki czemu obie strony mają do nich dostęp.
W rozdziale o AJAX omawialiśmy sobie protokół HTTP. Komunikacja między przeglądarką a serwerem odbywa się podobne do gry w tenisa. Przeglądarka pyta się o jakiś zasób, serwer odpowiada. W takiej komunikacji obie strony wysyłają sobie odpowiednie dane, do których dołączane są różne nagłówki. Przeglądarka wysyłając zapytanie do serwera wysyła "request headers". Gdy serwer odpowiada wraz z odpowiedzią wysyła "response headers".
Wśród tych nagłówków są dwa związane z przekazywaniem informacji o ciasteczkach.
Jeżeli kod tworzący ciasteczko został odpalony po stronie serwera, wraz z odpowiedzią wyśle on dla każdego ciastka nagłówek Set-Cookie. Przeglądarka odczyta taką odpowiedź, i jeżeli natrafi taki nagłówek automatycznie utworzy sobie odpowiednie ciastko.
I to właśnie ten kierunek jest tym najczęściej spotykanym. Serwer wysyła nam powyższy nagłówek z np. danymi autoryzacyjnymi, a nasza przeglądarka tworzy odpowiednie ciasteczko.
Wykonując kolejne zapytania do serwera przeglądarka będzie dołączać do nich informacje o ciasteczkach dla danej strony za pomocą nagłówka Cookie.
Po stronie serwera utworzyłem dla ciebie 2 ciasteczka: userid
i age
. Przejdź do zakładki Network w debuggerze, odśwież stronę i zbadaj pierwszy request na liście:
Ciasteczka obecne na danej stronie możesz sprawdzić na kilka sposobów. Wystarczy, że wpiszesz w konsoli debuggera document.cookie
- wtedy zobaczysz listę ciasteczek. O wiele lepiej jednak skorzystać z zakładki Application, w której pod zakładką Cookies znajdziesz wszystkie ciasteczka wraz z możliwością ich edycji i usuwania:

Ciasteczka możesz tworzyć zarówno na czas sesji (wtedy zostaną usunięte po zamknięciu przeglądarki), lub na czas który sam określisz. Dzięki temu możesz je wykorzystać nie tylko do przekazywania na serwer i z powrotem prostych danych, ale też do zapisania w przeglądarce kilku dodatkowych informacji dla użytkownika - np. jaką wybrał skórkę na stronie, czy wyraził chęć by go nie wylogować itp. W czasach kiedy nie mieliśmy dostępu do Storage, ciasteczka były główną formą zapisywania takich mikro informacji. W dzisiejszych czasach wygodniejsze jest używanie Storage, natomiast samych ciasteczek używamy wszędzie tam gdzie przydało by się mieć dostęp do tych danych po stronie serwera.
Większość skryptów z tego działu będziesz musiał odpalić z serwera lokalnego.
Obostrzenia względem ciasteczek są bardzo podobne do same-origin policy, czyli zabezpieczeń, które
nie pozwalają łączyć się asynchronicznie (ajax) gdzie tylko chcemy. Najczęściej ograniczeni jesteśmy do własnej domeny, chyba, że domena z którą się komunikujemy, ustawi odpowiednie nagłówki.
document.cookie
Powyżej powiedziałem ci, że do sprawdzenia listy ciastek na danej stronie możesz skorzystać z właściwości document.cookie. Właściwość ta służy zarówno do wyświetlania listy aktualnych ciastek dla danej strony, ustawiania nowych, ale też do ich usuwania. Nie jest to jednak właściwość, która odzwierciedla stan ciastek w 100%. Można ją traktować raczej jako mini interfejs służący do zarządzania nimi.
Gdy wpiszesz ją w konsoli, zobaczysz listę ciastek w postaci:
userid=810a37e4bb9152465d4c42e43c5af941; age=25; ...
Gdy przejdziesz jednak do zakładki Application w debuggerze, zobaczysz, że dane ciastka mają ciut więcej parametrów (patrz poniżej).
Gdy będziesz chciał utworzyć nowe ciastko, ustawisz tej właściwości nową wartość. Nie sprawi to jednak, że nadpiszesz wszystkie poprzednie ciastka, bo właśnie ustawiłeś całkowicie nową wartość. Nie - tylko dodasz nowe. Taka to specyficzna właściwość...
Tworzymy pierwsze ciasteczko
Stworzenie ciasteczka może być inicjowane po stronie serwera, ale tym bardziej możemy je stworzyć np. za pomocą Javascript.
Aby to zrobić, musimy w odpowiedni sposób ustawiając wartość dla właściwości document.cookie:
document.cookie = "nazwa=wartosc"
Ustawienie dla document.cookie nowej właściwości nie skasuje wszystkich poprzednio ustawionych ciastek, a utworzy nowe (jeżeli takiego nie ma).
Teoretycznie nazwa i wartość ciastka może zawierać dowolne znaki. Dla zachowania poprawnego formatowania, warto zastosować tutaj funkcję encodeURIComponent()
:
document.cookie = encodeURIComponent("nazwa użytkownika") + "=" + encodeURIComponent("Karol Nowak");
console.log(document.cookie); //"nazwa%20u%C5%BCytkownika=Karol%20Nowak"
Postać ciasteczka
Każde ciasteczko może składać się z kilku części:
document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT; secure"
- path
-
Oznacza zakres ciasteczka, czyli z jakiego adresu będzie do niego dostęp.
Jeżeli dla przykładu ustawimy
path=/user
, dostęp do tego ciasteczka będzie miała podstrona/user
,/user/inventory
ale już nie strona/pet
i potomne. - domain
-
Z jakiej domeny będzie dostęp do danego ciasteczka. Domyślnie ciasteczka są dostępne tylko z domeny, z której zostały ustawione.
Jeżeli ustawisz ciasteczko na adresie
test.com
, domyślnie nie będziesz miał do niego dostępu pod adresemauction.test.com
. Jeżeli chciałbyś by taki dostęp był możliwy, powinieneś ustawić domenę nadomain=test.com
:document.cookie = "user=John"; //na auction.test.com console.log(document.cookie); //""
document.cookie = "user=John; domain=test.com"; //na auction.test.com console.log(document.cookie); //"user=John"
- expires i max-age
-
Po ustawieniu ciasteczka będzie one aktywne do zamknięcia przeglądarki. Parametr expires oznacza datę do której dane ciastko będzie aktywne:
//plus jeden dzień od teraz let date = new Date(Date.now() + 86400e3); date = date.toUTCString(); document.cookie = "user=John; expires=" + date;
Ustawienie daty na mniejszą od obecnej spowoduje, że dane ciasteczko zostanie usunięte.
Alternatywnym zapisem dla expires jest
max-age
, który oznacza liczbe sekund od teraz, po których dane ciastko zostanie usunięte:document.cookie = "user=John; max-age=3600";
- secure
-
Domyślnie gdy założymy ciasteczko, dostęp do niego będzie możliwy zarówno z adresu
http://
jak ihttps://
. Jeżeli użyjemy parametru secure, dostęp będzie możliwy tylko zhttps://
:document.cookie = "user=John; max-age=3600; secure";
- httpOnly
-
Jeżeli serwer wyśle do nas nagłówek
Set-Cookie
, który będzie zawierał parametrhttpOnly
, nie będziemy mieli dostępu do tego ciasta z poziomu Javascript. - samesite
-
Parametr samesite służy głównie do zabezpieczenia przed atakiem CSRF czy Pixel Perfect.
Funkcje do tworzenia ciastek
Dla ułatwienia tworzenia ciastek wraz z parametrami, możemy utworzyć funkcję:
function setCookie(name, value, options) {
const opts = {
path: "/",
...options
}
if (navigator.cookieEnabled) { //czy ciasteczka są włączone
const cookieName = encodeURIComponent(name);
const cookieVal = encodeURIComponent(value);
let cookieText = cookieName + "=" + cookieVal;
if (opts.days && typeof opts.days === "number") {
const data = new Date();
data.setTime(data.getTime() + (opts.days * 24*60*60*1000));
cookieText += "; expires=" + data.toUTCString();
}
if (opts.path) {
cookieText += "; path=" + opts.path;
}
if (opts.domain) {
cookieText += "; domain=" + opts.domain;
}
if (opts.secure) {
cookieText += "; secure";
}
document.cookie = cookieText;
}
}
setCookie("mojeCiasteczko", "przykladowa wartość");
setCookie("mojeCiasteczko", "przykladowa wartość", { days: 10, path: "/" });
Odczyt ciasteczka
Aby odczytać dane ciasteczko, także skorzystamy z właściwości document.cookie.
function getCookie(name) {
if (document.cookie !== "") {
const cookies = document.cookie.split(/; */);
for (let cookie of cookies) {
const [ cookieName, cookieVal ] = cookie.split("=");
if (cookieName === decodeURIComponent(name)) {
return decodeURIComponent(cookieVal);
}
}
}
return undefined;
}
console.log(getCookie("mojeCiasteczko"));
Usuwanie ciasteczka
Aby usunąć dane ciasteczko musimy ustawić jego parametr expires na wcześniejszy od aktualnej daty:
function deleteCookie(name) {
const cookieName = encodeURIComponent(name);
document.cookie = cookieName + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
deleteCookie("darkTheme");
Może się jednak zdarzyć, że będziesz chciał usuwać ciasteczko, któremu wcześniej ustawiłeś właściwość path. W takim przypadku musisz także podać tą wartość:
function deleteCookie(name, options) {
const opts = {
path: "/",
...options
}
const cookieName = encodeURIComponent(name);
let cookieText = cookieName + "=";
if (opts.path) {
cookieText += "; path=" + opts.path;
}
cookieText += "; expires=Thu, 01 Jan 1970 00:00:00 GMT";
document.cookie = cookieText;
}
deleteCookie("darkTheme");
deleteCookie("darkTheme", {path: "http://kurs.js"});