Гоголев Сергей
Воронцов Максим
Семичев Олег
since 1994
document.cookie = 'name=Sergey';
document.cookie = 'age=30';
document.cookie = 'name=' + encodeURIComponent('Сергей');
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=forum.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';
var cookies = 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.name; // Sergey
localStorage.data = JSON.stringify({ name: 'Sergey' });
JSON.parse(localStorage.name); // { name: 'Sergey' }
window.addEventListener('storage', function (e) {
console.log(e);
});
{
key: 'name',
oldValue: 'Sergey',
newValue: 'Sergey Gogoleff'
}
Общение между окнами!
QUOTA_EXCEEDED_ERROR
localStorage in window
try {
localStorage.setItem('key', 'value');
localStorage.removeItem('key');
} catch (error) {}
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) {
t.executeSql(
'create table if not exists notes(' +
'id INTEGER PRIMARY KEY AUTOINCREMENT,' +
'title TEXT,' +
'created DATE)'
);
t.executeSql(
'insert into notes(title, created) values(' +
'"' + title + '","' + Date.now() +'")'
);
}, onError, onSuccess);
Абстракция над SQLite
Нет ограничений на размер*
Асинхронная
Не реляционная, а 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;
};
var request = window.indexedDB.open('db', 3);
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('public', 'public', { unique: false });
store.createIndex('name, public', ['name', 'public']);
}
}
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(e) {
var cursor = e.target.result;
if (cursor) {
console.log('Key: ', cursor.key);
console.dir('Data: ', cursor.value);
cursor.continue();
}
}
var transaction = db.transaction(['notes'], 'readonly');
var store = transaction.objectStore('notes');
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);
});