Esta semana, PouchDB v3.4.0 con compatibilidad con Couchbase Sync Gateway.
En este post, tomaremos el ejemplo existente de TodoMVC y agregaremos sincronización filtrada usando autenticación de Facebook. Además de la sincronización entre los clientes Web, vamos a cambiar el modelo de datos ligeramente para sincronizar con las aplicaciones ToDoLite existentes que se ejecutan en iOS y Android:
Para seguir adelante, puedes abrir y ejecutar el ejemplo TodoMVC en commit .d9bb961. Para mayor comodidad, he añadido el código de inicio de sesión de Facebook en app.js. Cuando el usuario inicia sesión, la función startSessionAndSync(accessToken, userId) se llama. ¡Ahora vamos a añadir el código para que esto suceda!
Inicio rápido
Asegúrate de servir la aplicación en el puerto 9000 ya que configuraremos CORS para localhost:9000 más tarde. El simple comando python debe hacer:
1 |
$ python -m SimpleHTTPServer 9000 |
Modelización de datos
TodoMVC y ToDoLite tienen un modelo de datos ligeramente diferente. En las apps ToDoLite, un usuario puede crear múltiples listas y compartirlas con múltiples usuarios.
En primer lugar, veamos un documento de Tarea con la información esperada título y una lista_id haciendo referencia a la Lista a la que pertenece (en este caso 123):
1 2 3 4 5 6 |
{ "_id": "E9W3-9I2Y-O8W2-6Y4D", "tipo": "tarea", "list_id": "123", "título: "Un título de tarea" } |
Del mismo modo, un documento de Lista también tiene un título y un propietario que hace referencia al usuario al que pertenece:
1 2 3 4 5 6 |
{ "_id": "123", "tipo": "lista", "título: "Lista TodoMVC", "propietario": "p:1234567890" } |
TodoMVC sin embargo es una aplicación de lista única. Para mantener las cosas simples podemos insertar el documento de la lista en código tan pronto como el usuario inicie sesión.
Vamos a crear una nueva función llamada migrateGuestToUser para crear el documento List con el id de usuario y guardarlo en PouchDB:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
función migrateGuestToUser(userId) { var lista = { _id: '123', tipo: lista, título: Lista TodoMVC, propietario: 'p:' + userId }; db.poner(lista, función(err, resultado) { si (!err) { consola.registro('Lista de usuarios guardada correctamente'); } }) } |
Nota: Es muy importante establecer el campo propietario, la función de sincronización rechazará el documento de lo contrario.
Y podemos llamarlo en startSessionAndSync:
1 2 3 |
función startSessionAndSync(accessToken, userId) { migrateGuestToUser(userId); } |
Los documentos de tarea pertenecen a una lista y, por tanto, tienen un lista_id que necesitamos establecer. Cambie la propiedad addTodo función en app.js para que se vea como abajo. Fíjese en que hemos definido el parámetro lista_id al campo _id de la lista que hemos insertado anteriormente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
función addTodo(texto) { var todo = { _id: nuevo Fecha().toISOString(), título: texto, comprobado: falso, tipo: tarea, lista_id: '123', fecha_de_creación: nuevo Fecha() }; db.poner(todo, función devolución de llamada(err, resultado) { si (!err) { consola.registro(Se ha enviado una tarea".); } }); } |
Ahora que tenemos los documentos apropiados que se ajustan al modelo de datos de ToDoLite, podemos echar un vistazo a la autenticación y la replicación.
Activación de CORS en Sync Gateway
En este tutorial, vamos a ejecutar una instancia local de Sync Gateway en localhost:4984 pero estamos sirviendo nuestra aplicación web en localhost:9000. En este punto obtendríamos un error de política de mismo origen. Pero Chris recientemente añadió soporte CORS a Sync Gateway para este propósito. Así que no tenemos que escribir una sola línea de código del lado del servidor :)
CORS permite a las aplicaciones web acceder a recursos de dominios distintos del dominio de origen. Al activar CORS en Sync Gateway le estamos diciendo al navegador "Sí, el nombre de dominio Sync Gateway puede comunicarse con esta aplicación web". Abrir sync-gateway-config.json con la configuración CORS adicional para habilitarlo en localhost:9000:
1 2 3 4 5 6 7 8 9 10 |
{ ... "CORS": { "Origen": ["http://localhost:9000"], "LoginOrigin": ["http://localhost:9000"], "Cabeceras": ["Tipo de contenido"], "MaxAge": 17280000 }, ... } |
Utilice Sync Gateway 1.1 o posterior. Inícielo con el archivo de configuración:
1 |
$ ~/Descargas/sync_gateway sincronizar-pasarela-config.json |
Volver a app.jsactualice la url de remoteCouch en consecuencia:
1 2 |
var SYNC_GATEWAY_URL = 'http://127.0.0.1:4984/todos/'; var remoteCouch = SYNC_GATEWAY_URL; |
Ahora bien, si intentáramos sincronizar la lista con Sync Gateway obtendríamos un error 401 No autorizado. Vamos a solucionarlo creando una sesión de usuario con el login de Facebook.
Autenticación con Sync Gateway
Para autenticarnos con Sync Gateway podemos enviar una solicitud POST a /todos/_facebook con el token de acceso, si recibimos un 200 OK, el navegador establecerá la cookie de sesión devuelta por Sync Gateway para futuras réplicas push/pull.
1 2 3 4 5 6 7 8 9 10 11 12 |
función startSyncGatewaySession(accessToken) { var solicitar = nuevo XMLHttpRequest(); solicitar.abra(POST, SYNC_GATEWAY_URL + /_facebook, verdadero); solicitar.setRequestHeader(Tipo de contenido, aplicación/json); solicitar.onreadystatechange = función() { si (solicitar.readyState == 4 && solicitar.estado == 200) { consola.registro('¡Nueva sesión de SG, comenzando sincronización!'); sincronizar(); }; solicitar.withCredentials = verdadero; solicitar.enviar(JSON.stringify({"access_token": accessToken})); } |
Nota: Es importante fijar request.withCredentials = true en una solicitud CORS para guardar la cookie devuelta por Sync Gateway para futuras solicitudes autenticadas (réplicas push/pull).
Llámalo startSessionAndSync pasando el accessToken volvimos de Facebook:
1 2 3 4 |
función startSessionAndSync(accessToken, userId) { migrateGuestToUser(userId); startSyncGatewaySession(accessToken); } |
Conclusión
Ahora abre tu navegador, puedes comprobar que los elementos de todo se sincronizan con otra ventana del navegador abierta o con las aplicaciones nativas que ejecutan TodoLite.
Los usuarios pueden seguir creando tareas sin estar conectados. Pero en cuanto un usuario inicia sesión, las tareas pasan a formar parte de su lista. Ofrecer una función de cuenta de invitado es una de las muchas ventajas de crear capacidades offline-first.
Fíjese en el Lista TodoMVC se muestra como una tarea en Chrome. Esto se debe a que en este ejemplo se utilizaba la función allDocs para visualizar las tareas.
En el próximo post, usaremos consultas Map/Reduce para añadir la capacidad multi-lista y también un documento de perfil para compartirlos con otros usuarios.
Más información:
- Configuración CORS de Sync Gateway: https://www.couchbase.com/developers/mobile/#cors-configuration
- Activación de cookies en una solicitud CORS: http://www.html5rocks.com/en/tutorials/cors/#toc-withcredentials
- Réplicas filtradas con PouchDB: http://pouchdb.com/2015/04/05/filtered-replication.html
Hola James, Gracias por el tutorial. Alguna idea de cómo habilitar CORS en la puerta de enlace de sincronización para la máquina de Windows?
la compilación del commit e8cf146. Puedo ejecutar esto en una máquina Windows?
Cuando intento ejecutar el sync_gateway con la configuración json, lanza:
XMLHttpRequest no puede cargar http://localhost:4984/todos/_facebook. No hay cabecera \'Access-Control-Allow-Origin' presente en el recurso solicitado. Por lo tanto, no se permite el acceso al origen "http://localhost:9000".
Gracias,
Nuthan.
Estoy usando Sync Gateway que construyo desde el master actual en Github. Se supone que incluye CORS y soporte PouchDB?
En mi caso no, el navegador me dice "No hay cabecera 'Access-Control-Allow-Origin' presente en el recurso solicitado".
En mi archivo config.json he añadido las líneas CORS:
\ "CORS\": {
\”Origin\”:[\”http://185.90.50.35:80\”],
\”LoginOrigin\”:[\”http://185.90.50.35:80\”],
\Encabezados: [Content-Type],
\"MaxAge": 1728000
}
¿Tiene idea de por qué? :)
CORS no me funciona !!!! todavía No \'Access-Control-Allow-Origin\'
¿alguna solución?
¿Está utilizando Sync Gateway 1.1? También puede seguir este tutorial para configurar CORS/PouchDB y las notificaciones Web Push https://github.com/couchbasela.... Avísame si sigue sin funcionarte.
En el vídeo tienes un navegador abierto con una página web. ¿Forma parte de Sync Gateway? ¿Hay que instalarlo por separado?
Intenté acceder a ella pero sólo me salía 404.
Gracias
No importa. La interfaz de administración sólo acepta conexiones desde 127.0.0.1
Hola James
CORS no funciona para mí.
ERROR:
XMLHttpRequest no puede cargar . La respuesta a la solicitud de verificación previa no pasa la comprobación de control de acceso: La cabecera \'Access-Control-Allow-Origin\' contiene el valor no válido \'\'. Por lo tanto, no se permite el acceso al origen .
En la sincronización de la solicitud tiene la url local para el origen y la puerta de enlace como el host. Pero el encabezado de respuesta > \ 'Access-Control-Allow-Origin'> es nulo y la solicitud está lanzando un 204 No Content .
La puerta de enlace de sincronización también se configuró para ORIGEN específico/Todas las URL, pero sigue teniendo el mismo problema.
CORS errores aquí también. He publicado la siguiente pregunta StackOverflow si alguien tiene tiempo para echar un vistazo:
http://stackoverflow.com/quest…