Cookies, LocalStorage, IndexedDB
Гоголев Сергей
document.cookie = 'name=Sergey';
document.cookie = 'age=30';
document.cookie = 'name=' + encodeURIComponent('Сергей');
%D0%A1%D0%B5%D1%D0%B3%D0%B5%D0%B9
document.cookie = 'age=30';
Ключ = name + path + domain
document.cookie = 'age=30; path=/';
document.cookie = 'age=30; path=/forum';
document.cookie = 'age=30; domain=example.org';
document.cookie = 'age=30; domain=beta.example.org';
GET /blog Host: beta.example.org GET /blog Host: example.orgGET /blog Host: old.example.org
document.cookie = 'age=30; path=/blog';
GET /blog GET /blog/list GET /blog/page/2GET /bloglist
document.cookie = 'name=Sergey;' +
'expires=Tue, 19 Apr 2016 00:00:00 GMT';
Устанавливаем дату устаревания в прошлом
document.cookie = 'name=Sergey;' +
'expires=Tue, 19 Apr 1970 00:00:00 GMT';
document.cookie = 'age=30; path=/';
document.cookie = 'age=30; path=/forum';
console.log(document.cookie);
age=30; age=30
/forum /
Cookies.set('name', 'Sergey', { expires: 7, path: '' });
Cookies.get('name');
Cookies.remove('name');
GET /forum HTTP/1.1 Host: example.org Cookie: name=Sergey; age=30
var express = require('express')
var app = express();
app.use(require('cookie-parser')())
app.use((res, req) => {
const cookies = req.cookies;
});
var express = require('express')
var app = express();
app.use((res, req) => {
res.cookie('age', 30, {
path: '/forum'
})
});
HTTP/1.1 200 OK Set-Cookie: age=30; path=/forum
var express = require('express')
var app = express();
app.use((res, req) => {
res.cookie('age', 30, {
httpOnly: true
})
});
HTTP/1.1 200 OK Set-Cookie: age=30; path=/forum; HttpOnly
Не доступны в js-скриптах на клиенте
var express = require('express')
var app = express();
app.use((res, req) => {
res.cookie('age', 30, {
secure: true
})
});
HTTP/1.1 200 OK Set-Cookie: age=30; path=/forum; secure
Не доступны по HTTP
Устаревание из коробки
Доступ с сервера из коробки
4kb
Передаются с каждым запросом
Cookieless домены для статики (CDN)
Храните id, а не полноценные данные
Обфусцируйте (01100101)
Инициализация состояния клиента
Авторизация
tools.ietf.org/html/rfc626510MB
5MB (Safari, iOS Safari)
2MB (Android Browser)
SessionStorage – хранит данные до окончании сессии (закрытие вкладки)
LocalStorage – хранит данные перманентно, пока скрипт или пользователь не удалит их
IE: ../DOMStore/YPHP6VDO/www.bing[0].xml Firefox: %profile/webappsstore.sqlite Chrome: User Data/Default/Local Storage/http_vk.com_0.localstorage
localStorage.setItem('name', 'Sergey');
localStorage.getItem('name');
localStorage.removeItem('name')
localStorage.clear();
localStorage.name = 'Sergey';
localStorage.obj = JSON.stringify({ name: 'Sergey' });
JSON.parse(localStorage.obj); // { name: 'Sergey' }
window.addEventListener('storage', function (event) {
console.log(event);
});
{
key: 'name',
oldValue: 'Sergey',
newValue: 'Sergey Gogoleff'
}
Простое общение между окнами
QUOTA_EXCEEDED_ERROR
localStorage in window
try {
localStorage.setItem('key', 'value');
localStorage.removeItem('key');
} catch (error) {
console.error(error);
document.cookie = 'key=value';
}
Private Browsing mode:
Error: SecurityError: DOM Exception 18
Modernizr.localstorage
Modernizr.cookies
Modernizr.audio
Modernizr.flash
Хранение настроек
Хранение промежуточных данных
Кеширование
10MB
Не передаёт данные на сервер
Сессионное хранилище из коробки
Общение между окнами
Строго ограничен доменом и схемой
Синхронный
html.spec.whatwg.org/multipage/webstorage.htmlАсинхронный интерфейс к SQLite базе
var db = window.openDatabase('db', '1', 'database', 32768);
db.transaction(function (t) {
transaction.executeSql(`
create table if not exists notes(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
created DATE
)
`);
transaction.executeSql(`
insert into notes(title, created)
values("${title}, "${Date.now}")
`);
}, onError, onSuccess);
Нет ограничений на размер*
Асинхронная
Не реляционная, а key-object
Не SQL, а API
Строго ограничен доменом и схемой
var request = window.indexedDB.open('db', 3);
request.onerror = function(event) {
console.log(event.target.errorCode);
};
request.onsuccess = function(event) {
var db = event.target.result;
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
if (!db.objectStoreNames.contains('notes')) {
var store = db.createObjectStore('notes', {
keyPath: 'id',
autoIncrement: true
});
store
.createIndex(
'name, public', ['name', 'public'],
{unique: false}
); // Для запросов с «where»
}
}
var transaction = db.transaction(['notes'], 'readwrite');
var store = transaction.objectStore('notes');
var note = {
id: 'films'
title: 'Films',
public: true
}
var request = store.add(note);
request.onerror = function (e) {}
request.onsuccess = function (e) {}
transaction.abort();
var transaction = db.transaction(['notes'], 'readonly');
var store = transaction.objectStore('notes');
var request = store.get('films')
request.onsuccess = function (e) {}
var transaction = db.transaction(['notes'], 'readonly');
var store = transaction.objectStore('notes');
var cursor = store.openCursor();
cursor.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
console.log(cursor.key);
console.dir(cursor.value);
cursor.continue();
}
}
var transaction = db.transaction(['notes'], 'readonly');
var store = transaction.objectStore('notes');
// store
// .createIndex(
// 'name, public', ['name', 'public'],
// {unique: false}
// );
var cursor = store
.index('name, public')
.openCursor(IDBKeyRange.only(['films', true]));
var db = new Dexie('MyDatabase');
db.version(1).stores({
notes: 'name, text'
});
db.open().catch(function (error){});
db
.notes
.where('name')
.equals(['Films'])
.each(function (note){
console.log(note.name);
});