Синхронизация localstorage между браузерами
Я ищу решение, которое позволяет localStorage браузера быть менее локальным, чтобы люди могли получить доступ к своим данным на нескольких устройствах. Традиционный способ - запустить базу данных на сервере и заставить людей войти в систему; но я пытаюсь избежать этого. Мне бы хотелось, чтобы серверная часть была легковесной - возможно, даже полностью статичной, если это возможно - и не имела бы задачи безопасного хранения паролей, заботы о защите данных и т. Д.
Многие браузеры имеют своего рода логин - учетную запись Google, Firefox и т. Д. - которые связывают браузеры пользователя вместе. Таким образом, идеальным решением было бы хранить данные в localStorage, но использовать эту учетную запись для синхронизации между устройствами. Существуют такие интерфейсы, как chrome.storage , которые кажутся доступными для упакованных приложений, но не для обычных веб-страниц.
Возможно ли что-то подобное с современными технологиями?
Я хотел бы рассмотреть возможность использования такого инструмента, как Firebase Web, он сэкономит вам массу времени на разработке и синхронизирует всех ваших клиентов с данными.
AFAIK нет хороших способов сделать то, что вы хотели бы сделать. Есть несколько хаков, но у каждого есть свои недостатки.
Оттуда вы можете сделать это для пользователей проблемой "синхронизации" страницы, позволяя им делиться URL, используя любой выбранный ими метод.
Недостатком, конечно, является синхронизация. У пользователя 2 браузера. Пользователь делится исходной ссылкой между браузером A и браузером B. Пользователь продолжает работать в браузере B. Теперь пользователь открывает браузер A: он не будет отражать изменения, сделанные в браузере B, если только URL не был передан снова, в другом направлении.
Я уже видел несколько примеров этой техники, где пользователь «загружал состояние приложения» в виде текста (опять же, в кодировке base64) и загружал этот текст при возвращении. Он был сформулирован как «создать резервную копию» и «восстановить резервную копию», что, возможно, более удобно для пользователя.
Вы можете использовать WebRTC без сервера сигнализации синхронизировать оба экземпляра вашего приложения.
Из вашего веб-приложения:
- опубликовать адрес электронной почты и пользовательские данные в бэкэнд (например, PHP)
С вашего бэк-энда:
сгенерируйте UUID и сохраните пользовательские данные в файле с именем UUID
На этом этапе у вас может быть статическая ссылка, которую вы можете:
Теперь вы можете получить пользовательские данные из серверной части, разместив этот UUID
Насколько безопасен UUID для хранения пользовательских данных? Я считаю, что UUIDv4 (созданный из «случайных данных» ) достаточно безопасен для создания достаточно уникальных идентификаторов. Итак, обратите внимание, как вы генерируете эти случайные семена. Вот отличная ссылка: PHP-функция для генерации UUID v4. Таким образом, эта статическая ссылка должна быть достаточно безопасной, и Вы можете использовать любую уже существующую систему аутентификации, чтобы поделиться этой ссылкой, по электронной почте или по своему усмотрению.
Вам нужно безопасное облачное хранилище для вашего приложения в браузере без необходимости обеспечения безопасности?
Вы можете сделать так, чтобы ваше приложение выполняло OAuth с GitHub через Auth0, и создавало приложение GitHub, которое пользователь добавляет в частное хранилище. Ваше приложение затем синхронизирует их данные в репо.
Затем GitHub обрабатывает идентификационные данные, Auth0 обрабатывает аутентификацию, а GitHub обрабатывает хранилище данных.
Вы можете использовать API, который сохраняет все данные . API для каждого пользователя после входа загрузить данные из серверной после этого сохранить в локальном хранилище
Привет! В этой статье я бы хотел поговорить про LocalStorage, его методы и особенности. Статью можно посмотреть в формате видео по этой ссылке. Ну что, приступим?
И так, что же это такое. LocalStorage это свойство объекта window, предназначенное для хранения пар ключ/значение в браузере. В зависимости от браузера, мы можем сохранять до 5 мб данных. Но тогда возникает логичный вопрос, зачем нам localStorage, если данные мы можем сохранять данные в обычных переменных? Ответ очень прост, все что мы запишим в localStorage, останется там после перезагрузки страницы и даже после закрытия браузера. Теперь поговорим о том как мы можем взаимодействовать с localStorage.
Запись в LocalStorage
Чтобы сохранить данные можем использовать метод setItem(key, value) у localStorage. Этод метод принимает два аргумента: ключ по которому мы будем сохранять информацию и само значение, которое мы хотим сохранить. Например:
Для просмотра наших записей надо открыть DevTools там найти вкладку Application и там обязательно будет LocalStorage
Чтение из LocalStorage
Теперь конечно же хочется получить эти данные. Для этого воспользуемся методом getItem(key) . Результат можно вывести в консоль, или сохранить в переменную.
Только строки
Как видите, все просто, но есть один маленький нюанс. Значение, которое мы записываем должно быть строкой. Давайте попробуем добавить поле age со значением 5. Для этого напишем:
Сохраняем файл. И что мы видим? Ошибок никаких нет, а если перейти во вкладку Application, то мы увидим что запись прошла успешно. Это конечно же так, но при записи пятерка стала строкой, то есть была автоматически приведена к типу string. Это не то чтобы плохо, но может привести к неожиданному поведению, к примеру при строгом сравнении. Я бы советовал привести строку к числу, это можно сделать вот так:
Если с примитивами все просто, то что на счет объектов? Создадим объект user и попробуем записать его в LocalStorage:
Переходим во вкладку Application и видим [objectObject] .
И есть одна небольшая проблемка у этой строки не будет полей, которые мы определили в объекте user. Это просто обычная строка. И в исходный вид это уже никак не вернуть. Для того, чтобы записать объект в localStorage надо сделать его строкой. У нас как раз есть прекрасный формат под это, и имя его json . Для преобразования объекта в строку нужно использовать JSON.stringify :
Теперь все записалось корректно:
Чтобы получить объект в первозданном состоянии используем метод parse у JSON :
Полученый результат можем записать в консоль, или сохранить в переменную.
Удаление из LocalStorage
Мы научились записывать и получать элементы, теперь надо научится их удалять. Для этого будем использовать метод removeItem(key) который удалит поле с ключом key .
Так же во вкладке Application мы можем выделить нужный нам рядок и нажать на крестик, что тоже приведет к удалению.
Очистка LocalStorage
Чтобы очистить все поля мы можем использовать метод clear() :
Вариант из Application:
Я рекомендую так делать, только тогда, когда вы на 200% уверены что все данные заносили только вы, и после удаления чего либо ваш сайт не начнет вести себя некорректно.
Событие storage
Если у вас есть потребность, или желание прослушивать изменение в localStorage, то можно просто добавить слушатель событий на 'storage' :
При каждом изменении localStorage генерируется событие storage. Оно отрабатывает на всех вкладках, на которых открыт наш сайт, кроме той, где мы создали это событие. В event хранятся название поля которое мы затронули, старое значение, новое значение, url документа и storageArea. Если интересно, крайне рекомендую переписать этот кусок кода себе, открыть две вкладки вашего локалхоста и посмотреть как это работает.
Также, надо держать в голове что самый "топовый" браузер, то бишь IE вызывает событие 'storage' даже если данные не изменились, что является некорректным поведением. Поэтому если вам не пофиг на екплоер и вы не хотите каких-то нежданчиков, то надо явно сравнивать новое и старое значение, которые мы можем получить из event .
Давным-давно в далёкой галактике появилась задача по синхронизации вкладок браузера для веб-плеера, наподобие VK: нужно было организовать обмен данными между вкладками, отслеживать их количество и назначать задачи некоторым из них. Всю реализацию нужно было выполнить на клиенте. Информации собрано много, и набралось на целую статью.
Ниже опишу различные способы решения подобных задач.
Рассмотрим наиболее популярные способы синхронизации вкладок браузера в порядке увеличения сложности.
Local Storage
localStorage – локальное хранилище, свойство объекта window, позволяет получить доступ к локальному Storage объекту. В нем можно хранить данные между сессиями пользователя. Есть аналогичное свойство – sessionStorage, но оно хранит данные только в течение сессии страницы.
Данные в storage добавляются с помощью метода setItem.
Событие storage идеально подходит для синхронизации данных между вкладками, оно генерируется при изменении значения элемента localStorage или sessionStorage.
Событие не работает на вкладке, которая вносит изменения, но срабатывает на остальных вкладках домена в браузере.
Генерация события storage
Браузеры имеют различный уровень объема хранилищ для localStorage и sessionStorage:
- Chrome, FireFox и Opera ~ 5 МБ.
- IE ~ 4,8 МБ.
- iOS Safari, OS X Safari ~ 2,5 МБ.
- Android ~ 5 МБ.
Post Message
Передаваемые данные могут быть любым объектом, который поддерживает клонирование (строка, объект, массив, Map, Date . ). Но IE поддерживает только строки.
В браузере IE интерфейс postMessage работает только с iframes и не работает между вкладками и окнами.
Broadcast Channel API
На первый взгляд можно найти несколько похожих методов передачи данных (например MessageChannel, WebSocket), но каждый из них служит определенной цели — их сравнение.
Web Workers
Воркеры отлично подходят для того, чтобы выполнять тяжелые вычислительные операции, не замедляя работу пользовательского интерфейса.
Но с синхронизацией помочь могут только два вида воркеров.
Shared Worker
Это особый вид воркера, к которому можно получить доступ из нескольких контекстов браузера. Напишем общий js-файл для вкладок, например shared-worker.js.
Каждая вкладка может связываться с воркером через worker.port. Скрипт воркера также имеет доступ к своим портам. Каждый раз, когда вкладка подключается к воркеру, в сценарии запускается событие connect.
Метод postMessage создан для отправки данных вкладки на общий воркер.
Получить данные воркера можно с помощью события message.
В SharedWorker API есть событие connect, но нет события disconnect, и поэтому данные не смогут самоочищаться в закрытых вкладках — они будут продолжать считаться открытыми. Это не приведет к ошибкам, но можно считать это недоработкой или фичей API.
Работает только в Chrome и FF.
Service Worker
Подробное использование и множество примеров тут.
У всех веб-воркеров нет доступа к объектам window и document.
Service worker не работает в IE и Opera mini.
Библиотеки синхронизации
Это способ для тех, кто не хочет велосипедить и готов рассмотреть уже имеющиеся решения.
-
, использует Сookie и Local Storage; , использует SharedWorker; , использует Page Visibility API; , использует Local Storage и WebSocket; , использует Worker и localStorage;
Чтобы подвести окончательные итоги, сравним методы по поддержке браузерами наглядно.
Для управления блокировками совместного состояния и совместных файлов наиболее подходящим решением является Shared Workers и Service Worker.
А для задачи с веб-плеером был выбран LocalStorage, так как есть поддержка IE.
Надеюсь, что статья помогла вам в выборе подходящего способа синхронизации.
На протяжении многих лет возможности браузеров постоянно увеличивались в ответ на растущие потребности веб-приложений. И теперь у нас есть множество способов получения одной и той же (или схожей) функциональности. На такую особенность браузеров, как возможность обмена данными между вкладками, редко обращают внимание. Рассмотрим несколько сценариев, в которых она может потребоваться:
- Изменение темы (например, тёмная или светлая тема) приложения распространяется на уже открытые вкладки браузера.
- Получение последнего токена для аутентификации и использование его во всех вкладках браузера.
- Синхронизация состояния приложения во всех вкладках браузера.
На момент написания этой статьи существовало несколько достойных внимания подходов, в соответствии с которыми осуществляется обмен данными между вкладками браузеров. У каждого из этих подходов свои сильные и слабые стороны, поэтому остановимся на них подробнее, чтобы вы могли найти подходящий для вас вариант.
Возможно, вы уже использовали LocalStorage , который доступен на разных вкладках в рамках одного и того же приложения-источника. Но знаете ли вы, что LocalStorage поддерживает события? Эту функцию можно использовать для обмена данными между вкладками браузера: хранилище обновляется, после чего событие получат другие вкладки.
Например, в одной вкладке выполняется следующий код JavaScript:
И другие, прослушивающие событие вкладки получат это событие:
Но здесь есть несколько ограничений:
- Событие не срабатывает для вкладки, на которой выполняется действие по вводу значений в хранилище.
- Этот подход имеет негативные последствия для большого объёма данных: из-за синхронности выполняемых в LocalStorage действий основной поток пользовательского интерфейса может быть заблокирован.
API широковещательного канала позволяет осуществлять обмен данными между вкладками, окнами, фреймами, Iframes и веб-воркерами. Одна вкладка создаёт что-то и опубликовывает это на канале:
А другие вкладки прослушивают канал:
И таким образом происходит обмен данными между контекстами браузера (окнами, вкладками, фреймами или Iframes). Такой способ обмена данными между вкладками браузера очень удобен. Тем не менее safari и IE его не поддерживают. Более подробная информация содержится в разделе «BroadcastChannel» документации MDN.
Подсказка: выкладывайте на Bit (Github) переиспользуемые компоненты для своих проектов. Здесь очень просто размещать, документировать и организовывать независимые компоненты из любого проекта.
Задействуйте этот ресурс для максимально многократного использования кода и совместной работы над независимыми компонентами, а также для создания масштабируемых приложений.
Bit поддерживает Node, TypeScript, React, Vue, Angular и много других инструментов.
А принимающий воркер на другой вкладке браузера прослушивает это событие:
А целевое окно прослушивает события:
Одно из преимуществ этого подхода перед другими — возможность поддержки обмена данными между разными источниками. Но есть и ограничение: необходима ссылка на другую вкладку браузера. Поэтому этот подход только для вкладок браузера, открытых через window.open() или document.open() . Более подробная информация содержится в документации MDN.
Надеюсь, статья была для познавательной и рассмотренные в ней подходы будут полезны для ваших веб-приложений. Каждый подход уникален и имеет свои варианты использования.
Кроме этих четырёх подходов, для обмена данными между вкладками браузера и даже между устройствами в режиме реального времени применяются Websockets («веб-сокеты») и Server-Sent Events («события, посылаемые сервером»). Но для этого понадобится веб-сервер. А вот рассмотренные в статье подходы не зависят от веб-сервера, и их применение позволяет осуществлять обмен данными в браузере без него и делать это быстро.
Один из простых вариантов для сохранения состояния — использовать localStorage в браузере. Рассмотрим пример:
В этом компоненте с состоянием имеется count . Теперь предположим, что нам надо при перезагрузке страницы сохранить значение этого счетчика count . Для этого просто задействуем localStorage :
Теперь при задействовании localStorage в компоненте с состоянием значение этого состояния сохраняется, когда вызывается метод setState .
Это простой подход для сохранения состояния в классовых компонентах. Посмотрим, как добиться того же в функциональном компоненте.
Первым делом преобразуем компонент, основанный на классах, в функциональный компонент:
A теперь посмотрим, как при добавлении localStorage в функциональный компонент с состоянием добиться сохранения этого состояния:
В случае с функциональным компонентом применен несколько иной подход. Здесь использован хук useEffect , и сделано это для:
- Отслеживания изменений и обновления LocalStorage .
- Получения сохраненного значения из LocalStorage при инициализации.
Но при сохранении состояния в localStorage на уровне компонента возникает одна проблема. И связана она с наличием нескольких экземпляров одного и того же компонента. Это приводит к неожиданному поведению, так как в localStorage создаются повторяющиеся ключи.
У этой проблемы два решения:
- Передать идентификатор в повторно используемый компонент и задействовать его для хранения значения в localStorage .
- Или сохранять состояние на более высоком уровне.
Для сохранения состояния приложения в localStorage будем использовать Redux.
Здесь при использовании localStorage с Redux мы подписываемся на обновления хранилища и сохраняем это в localStorage . А при инициализации приложения передаем исходное состояние из localStorage .
Обратите внимание: здесь пригодится популярная библиотека Redux Persist.
А сохранять и инициализировать persistStore нам помогает persistReducer из Redux Persist.
Наконец добрались до самого очевидного варианта — использования параметров URL для сохранения состояния. А этот подход годится, в случае если данные предельно простые и со значениями-примитивами. Это обусловлено ограничениями по длине URL.
Если приглядеться к этому коду, то мы заметим, что он добавляет состояние в историю браузера. Поэтому при инициализации компонента мы наследуем исходные значения параметров URL.
Для сохранения состояния приложения на React используются localStorage и параметры URL.
В простой ситуации вполне сгодятся параметры URL. Если данные немного сложнее, стоит отдать предпочтение сохранению состояния в localStorage . В случае с localStorage решаем, где сохранять состояние: на уровне компонентов или на уровне приложений.
Чтобы упростить себе задачу и не заниматься сохранением и восстановлением состояния приложения вручную, задействуем библиотеки типа Redux Persist.
Какой бы вариант вы не выбрали, важно также сохранять контроль над изменениями состояния. Ведь после того, как состояние будет установлено, у некоторых пользователей приложение не сможет продолжать работу, если в более новой версии вы измените код, связанный с этим состоянием.
Читайте также: