Cómo extender localStorage a través de dispositivos (sin DB)

10

Objetivo: extender mi ya implementado localStorageen mi aplicación, para estar bien, no local, supongo.


Me gusta la implementación de guardar configuraciones de usuario simples con API de almacenamiento local. Tengo esto funcionando para mis necesidades en una aplicación web, pero el único problema es que es local para esa máquina / navegador que se usa / guarda. No tengo acceso a una tabla de estilo MySQL clásica para esto. Me gustaría ampliar o adaptar mi almacenamiento local para transferirlo a otros navegadores; o almacenar mi configuración de usuario en objetos JS de usuario y propiedades de objeto JS.

  • Me gusta la idea de crear simplemente objetos JSON o JavaScript con cada usuario, siempre que haya un nuevo usuario, tome el nombre, cree un objeto o object[key]con el nombre, y tenga las propiedades predeterminadas de las propiedades de campo al principio, y las variables se llenen y / o anulado cuando el usuario los guarda.
  • O si lo anterior está mal visto; me gustaría mantener mi implementación de almacenamiento local, ya que funciona muy bien y encontrar un complemento / biblioteca / extensión de algún tipo que me permita también guardar esto y volver a renderizar en diferentes ubicaciones; Esto ha llegado a ser pensado antes. Aunque me encantaría mantenerlo del lado del cliente; Estoy abierto a una solución de node.js así como a una solución de python, un tipo de marco de datos simple debería funcionar lo suficiente.
  • ¿Qué pasa con la generación de un archivo con mis localStoragedatos? ¿Quizás un archivo .csv (esto es información no confidencial) y que se actualice como lo localStoragehace mi
doc vacaciones
fuente
2
No puede hacer esto solo del lado del cliente. Para conservar la información del usuario en todos los navegadores, necesita un servidor público y almacenar información en él. Típicamente esto se hace usando una base de datos; Si no desea utilizar mySQL, hay otros tipos de almacenamiento de datos. Firebase está bastante cerca de lo que imaginas, te permite almacenar objetos de estructura arbitraria. (también, JSON es un formato de texto. No existe un objeto JSON)
Chris G
algo similar a eso: stackoverflow.com/a/60279503/4845566 ?
Deblocker

Respuestas:

3

¿Qué pasa con el uso de sqlite?

Solo un archivo en su servidor como csv. Envío de una solicitud http Para actualizarla utilizando la instrucción SQL de knex o algo así después de actualizar el almacenamiento local en el lado del cliente.

Al menos es mejor que cvs, creo, porque puedes definir varias tablas, que es más escalable y más eficiente, ya sabes, es una base de datos.

kobako
fuente
2

Estoy agregando mis dos centavos aquí.


Exportar / Importar archivo (JSON, XML, CSV, TSV, etc.)

Exportar:

Serialice la configuración y descárguela como archivo.

Importar:

Abra el archivo de configuración serializado exportado / descargado.

Código de ejemplo:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Settings Export/Import Demo</title>
</head>

<body>
    <div id="display"></div> <br>
    <button onclick="exportSettings();">Export</button>

    <button onclick="resetSettings();">Reset</button> <br><br>
    File to import: <input id="file-input" type="file" accept="application/json"> <br>
    <button onclick="importSettings();">Import</button>
    <script>

        function exportSettings() {
            var json = getSettingsAsJSON();
            var blob = new Blob([json], { type: "application/json" });
            var linkElement = document.createElement("a");

            linkElement.href = URL.createObjectURL(blob);
            linkElement.download = "ThisIsMySettings";

            document.body.appendChild(linkElement);

            linkElement.click();

            document.body.removeChild(linkElement);
        }

        function importSettings() {
            var fileInput = document.getElementById("file-input");

            if (fileInput.files.length > 0) {
                var jsonFile = fileInput.files[0];

                var fileReader = new FileReader();

                fileReader.onload = function (e) {
                    var json = e.target.result;

                    try {
                        var settings = JSON.parse(json);

                        if (settings.hasOwnProperty("userId")) {
                            localStorage["myapp_user_id"] = settings.userId;
                        }

                        if (settings.hasOwnProperty("hello")) {
                            localStorage["myapp_hello"] = settings.hello;
                        }

                        if (settings.hasOwnProperty("data")) {
                            localStorage["myapp_data"] = settings.data;
                        }

                        displaySettings();
                    } catch (ex) {
                        console.error(ex);

                        alert("Error occured while importing settings!");
                    }
                };

                fileReader.readAsText(jsonFile);
            }
        }

        function resetSettings() {
            localStorage["myapp_user_id"] = Math.floor(Math.random() * 100000) + 1;
            localStorage["myapp_hello"] = "Hello World!";
            localStorage["myapp_data"] = JSON.stringify([1, 3, 3, 7]);

            displaySettings();
        }

        function displaySettings() {
            var json = getSettingsAsJSON();

            document.getElementById("display").innerText = json;
        }

        function getSettingsAsJSON() {
            return JSON.stringify({
                userId: localStorage["myapp_user_id"],
                hello: localStorage["myapp_hello"],
                data: localStorage["myapp_data"]
            });
        }

        resetSettings();
    </script>
</body>

</html>

URL (cadena de consulta)

Exportar:

Codifique la configuración en una cadena de consulta y combínela con la URL actual como hipervínculo.

Importar:

Visite el hipervínculo que contiene la cadena de consulta con la configuración codificada, luego JavaScript detecta y carga la configuración de la cadena de consulta.


Datos codificados Base64

Exportar:

Serialice la configuración, luego codifíquela como cadena Base64 y luego cópiela en el portapapeles.

Importar:

Pegue la cadena Base64 del portapapeles en el cuadro de texto para decodificar, deserializar y cargar la configuración.


Código QR

Exportar:

Codifique la configuración en una cadena de consulta y combínela con la URL actual como hipervínculo. Luego genere una imagen de código QR y visualícela.

Importar:

Escanee la imagen del código QR generada y visite el hipervínculo automáticamente.


Servidor HTTP (Node.js) / Almacenamiento en la nube (AWS S3)

Exportar:

HTTP POST al punto final automáticamente al actualizar valores, por ID de usuario.

Importar:

HTTP GET desde el punto final por ID de usuario.


Extra: PouchDB

La base de datos que se sincroniza

PouchDB es una base de datos JavaScript de código abierto inspirada en Apache CouchDB que está diseñada para ejecutarse bien dentro del navegador.

PouchDB se creó para ayudar a los desarrolladores web a crear aplicaciones que funcionen tan bien sin conexión como en línea. Permite que las aplicaciones almacenen datos localmente mientras están fuera de línea, luego los sincroniza con CouchDB y servidores compatibles cuando la aplicación vuelve a estar en línea, manteniendo los datos del usuario sincronizados sin importar dónde inicien sesión.

DK Dhilip
fuente
Gracias por la respuesta. El mejor hasta ahora; con la primera importación / exportación: ¿podría hacerlo para que el usuario simplemente pudiera abrir el archivo para cargar la configuración? ¿Cómo podría funcionar eso?
doc vacaciones
1
Código de ejemplo agregado para la exportación / importación de archivos JSON.
DK Dhilip
Ah, ya veo. Gracias. Simplemente creo que es demasiado pedir al usuario. Si hubiera una forma de generar un hipervínculo y enviarlo por correo electrónico, tal vez. Creo que mis datos contienen demasiados caracteres para poner en una cadena de consulta de URL. ¿Cómo se escanearía la opción del código QR?
doc feriado
Si sus datos son demasiado grandes para caber en la cadena de consulta, ¿tal vez podría experimentar con gzip / deflate más Base64 para ver si puede reducir el tamaño de la carga útil e incluirlo en la cadena de consulta? No sé si esto funcionará lo suficientemente bien para su caso, solo un pensamiento aleatorio. Para la opción de código QR, podría ser escaneado por cualquier dispositivo con una cámara, o escanear el archivo de imagen directamente (desde URL normal, URL de datos, archivo abierto).
DK Dhilip
Para expandir la idea de reducción de tamaño de datos, también puede intentar serializar manualmente sus datos en ArrayBuffer para hacerlo lo más pequeño posible y luego aplicarle la codificación Base64 según el método de transporte.
DK Dhilip
2

Puede usar la URL como almacenamiento si comprime sus parámetros de usuario.
obtenga los parámetros que desea almacenar> json> desinflar> codificar en base64> insertar en la URL

const urlParam = btoa(pako.deflate(JSON.stringify(getUser()), { to: 'string' }));

onload: obtener los parámetros de la url> decodificar desde base64> inflar> analizar json

const user = JSON.parse(pako.inflate(atob(urlParam), { to: 'string' }));

https://jsfiddle.net/chukanov/q4heL8gu/44/

El parámetro de URL será bastante largo, pero 10 veces menos que el máximo disponible.

Anton Chukanov
fuente
¡Esta! Sin embargo, cuando registro la consola, mis datos de almacenamiento local son ~ 20k y ~ 8k en caracteres. ¿Todavía podría hacer algo como esto?
doc feriado
1
He probado con 160k caracteres. Serán 1600 caracteres después de desinflar, incluso IE funcionará sin problemas (longitud máxima de la URL, es decir, 2048). Los navegadores modernos no tienen limitaciones para la longitud de la URL.
Anton Chukanov
¡Gracias! ¿Pako requiere una biblioteca o algo? Me estoy poniendo pako indefinido
doc holiday
1
"Los navegadores modernos no tienen limitación para la longitud de la URL" es una suposición falsa, por favor refiérase a esto . Además, pako es una biblioteca de JavaScript que se puede encontrar aquí ( GitHub , cdnjs ). Por último, tenga en cuenta que la relación de compresión puede variar según el contenido de los datos.
DK Dhilip
2

En lugar de usar localstorage, almacene la configuración de su usuario en el Sistema de archivos interpalanetario (IPFS) https://ipfs.io/

Básicamente, pondría su configuración en un formato de datos como JSON y luego lo escribiría en un archivo y lo enviaría a IPFS.

Necesitará una forma de identificar qué datos van a qué usuario. Tal vez podría usar un hash del nombre de usuario y contraseña para nombrar sus archivos o algo así. Entonces su usuario siempre podrá acceder a su contenido en cualquier dispositivo (siempre y cuando no olvide su contraseña).

Michael Babcock
fuente
1

Puede usar una biblioteca llamada localForageque básicamente tiene la misma API que, localStorageexcepto que le permite almacenar estructuras de datos más complejas (matrices, objetos) y también admite nodejsdevolución de llamada de estilo, promesas y async await.

Aquí hay un enlace al repositorio donde puede encontrar ejemplos de usos y cómo implementarlo en su proyecto de la manera que desee.

C.Gochev
fuente
Gracias que se ve bien; pero parece que tiene las mismas limitaciones para una base de datos que el localStorage normal
doc feriado
1

La mejor manera de implementar esto sin usar la base de datos para compartir datos, creo que está basado en la solución WebRTC , pensé en ello como una forma de hacerlo, pero no tengo código para ello (al menos por ahora), así que con alguna búsqueda encontré que alguien ya lo hizo (no exactamente, pero con algunos ajustes estará listo) aquí, por ejemplo, y es parte de este artículo webrtc sin un servidor de señalización

aquí hay una fuente más: demostración del ejemplo básico del canal de datos

y en github: ejemplo básico del canal de datos

WebRTC no es solo para video / audio chat, también se puede usar en mensajes de texto y colaboración en edición de texto.

Esta solución incluso se menciona en una de las respuestas aquí .

Ma'moun othman
fuente
0

Utilice cookies o tenga un archivo descargable que los usuarios puedan llevar consigo para cargarlo cuando accedan a otro navegador. Puede hacer esto con un archivo de texto, JSON o JavaScript con datos de objetos.


fuente
¿Creo que las cookies también son locales?
doc feriado
Las cookies de terceros pueden ser utilizadas por múltiples sitios web si se basan en la misma "fuente".
0

Puedes usar Redis . Es un almacén de estructura de datos en memoria, utilizado como base de datos. Puede almacenar sus datos en formatos de pares de claves. También hace que su aplicación sea rápida y eficiente.

Deeksha gupta
fuente
0

Obviamente, el mejor enfoque es utilizar una base de datos. Sin embargo, si está inclinado a usar una base de datos, entonces un mejor enfoque posible es usar una combinación de técnicas que creo que ya mencionó, así que lo ayudaré a conectar los puntos aquí.

Pasos necesarios:

  1. API LocalStorage (ya que ya está funcionando parcialmente para usted).
  2. Cree un punto final Node o Python (o con lo que se sienta cómodo) para obtener los datos de configuración GET y POST.
  3. Cree un archivo userSettings.JSON en su servidor API.

Instrucciones:

Usaría su localStorage de la misma manera que lo está usando ahora (estado de trabajo actual).

Para mover o tener configuraciones de usuario en diferentes dispositivos, se usará un archivo userSettings.JSON (que sirve como base de datos de documentos) para almacenar e importar configuraciones de usuario.

Su punto final de API se usaría para OBTENER configuraciones de usuario si no existe ninguna en localStorage. En la actualización de la configuración, actualice su almacenamiento local y luego PUBLICAR / ACTUALIZAR la nueva configuración en su archivo userSettings.JSON utilizando su punto final.

Su punto final de API solo se usará para mantener (leer y escribir) el archivo userSettings.JSON. Necesitará un método / función para crear, actualizar y quizás eliminar configuraciones en su archivo. Como ya sabrá, un formato de archivo JSON no es muy diferente de una base de datos MongoDB. En este caso, solo está creando los métodos que necesita para administrar su archivo.

¡Espero que esto ayude!

mohammedabdulai
fuente
-1

Puede resolver esto sin una base de datos, pero no lo recomendaría. Básicamente tiene pares (usuario, localStorage) y cuando un usuario determinado se identifica a sí mismo, su localStorage debe proporcionarse de alguna manera. Puede decirles a los usuarios que almacenen sus almacenes locales en su propia máquina, pero luego tendrán que copiarla en otras máquinas, lo que requiere mucho trabajo y nunca ganará popularidad. Uno podría ejecutar manualmente un fragmento de Javascript en la consola de su navegador para asegurarse de que localStorage tenga sus datos y tener que copiar el localStorage en todas las máquinas es solo un poco más fácil que hacerlo manualmente.

Puede poner la información de localStorage codificada en una URL, pero además del problema de la longitud de la URL, que podría convertirse en un problema y los problemas de codificación siempre presentes, un tercero puede monitorear su localStorage completo, teniendo acceso a su enrutador. Sé que has dicho que los datos no son confidenciales, pero creo que todavía no lo son . Pero una vez que los usuarios usen esto, si es conveniente, también almacenarán datos confidenciales o, sus clientes podrían tener tales tareas para usted, o incluso podría darse cuenta de que necesita almacenar datos allí que no sean 100% públicos.

Además de estos, en la práctica enfrentará problemas muy serios de sincronización, es decir, es bueno hacer que agnóstico localStorage, pero entonces, ¿cuál es la versión real? Si trabaja regularmente en 10 sesiones diferentes, sincronizar localStorages se convierte en un problema difícil. Esto significa que localStorage debe tener una marca de tiempo.

Por lo tanto, necesitará un lugar central, un servidor para almacenar la última versión guardada localStorage. Si las bases de datos lo evitan por razones desconocidas, puede almacenar localStorages dentro de archivos que identifican al usuario, como

johndoe.json

y luego, deberá implementar una función de exportación, que enviará el JSON actual del usuario al servidor y lo guardará en un archivo y una función de importación, que descargará el archivo almacenado para el usuario y garantizará que localStorage se actualice en consecuencia. También puedes hacer los dos juntos, implementando una sincronización.

Esto es simple hasta ahora, pero ¿qué pasa si el usuario ya tiene algunos datos útiles dentro de su localStorage local y también en el servidor? El enfoque más simple es anular uno con otro, pero ¿cuál? Si estamos importando, se anula el local, si se exporta, se anula el del servidor, si sincronizamos, se anula el anterior.

Sin embargo, en algunos casos desea fusionar dos Almacenes locales del mismo usuario, por lo tanto:

nuevos elementos

Creo que si un elemento es nuevo, se debe saber de alguna manera que se creó en esta sesión, lo que es útil saber, porque eso significa que en la otra sesión con la que nos estamos fusionando, este nuevo elemento no se eliminó y por lo tanto, es intuitivo agregarlo.

cambios de elementos

Si el mismo elemento es diferente en los dos casos, entonces prevalecerá la versión más nueva.

elementos eliminados

El caso interesante es cuando en una sesión se eliminó y en la otra se actualizó. En este caso, creo que el cambio más reciente debería prevalecer.


Sin embargo, a pesar de sus mejores esfuerzos, los usuarios aún pueden estropear (y su software también) las cosas, por lo que hacer copias de seguridad de cada sesión en su servidor tiene sentido.

Lajos Arpad
fuente