Persistencia de datos y sesiones con React
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)



Tener una función de "recordarme" es una característica muy útil, y la implementación con React y Express es relativamente fácil. Continuando desde nuestra última parte donde creamos una aplicación de chat WebRTC, ahora vamos a añadir Mongo-backed sesiones persistentes y una base de datos respaldada lista de usuarios en línea para una buena medida.
¿Sesiones?
Si
no has utilizado las sesiones antes, en resumen son bastante similares a
las cookies, en que las sesiones le permiten realizar un seguimiento de
los usuarios activos de su aplicación en tiempo real. Las
sesiones realmente funcionan a través de una session cookie, que se
envía en los encabezados de solicitud / respuesta de su aplicación.
Así que las cookies y las sesiones están entrelazadas por la naturaleza. Entonces, ¿por qué necesitamos sesiones si ya tenemos cookies? Lo que las sesiones le dan además es la capacidad de definir el almacenamiento back-end utilizado por la parte del servidor de su aplicación. Esto significa que cada vez que la información es requerida por su aplicación, se puede recuperar de la base de datos.
Así que en un ejemplo de la vida real para nuestra aplicación de chat, ahora podemos almacenar el nombre de usuario del usuario—y si reconfiguramos algo nuestra aplicación, también insertamos todo el historial de chat en la base de datos para el registro.
En este próximo ejemplo usaremos una base de datos Mongo para el almacenamiento persistente de fondo. Esta es una de las varias opciones disponibles para el almacenamiento de sesión, y otra que recomiendo para las configuraciones de producción a gran escala con múltiples servidores web es memcache.
Almacenamiento de documentos
Mongo es un motor de almacenamiento de documentos NoSQL en lugar de un almacén de datos relacional, como el popular MySQL. NoSQL es realmente fácil de conseguir su cabeza alrededor si usted viene de MySQL o de bases de datos similares y necesita ponerse al día con Mongo—no le tomará mucho. Las diferencias más grandes que usted debe saber son las siguientes:
- Como dice el nombre, NoSQL no utiliza SQL para realizar consultas. En su lugar, los datos se abstraen con llamadas de método; Por ejemplo
db.collectionName.find()Sería unaSELECT * FROM table - La terminología es diferente: en MySQL tenemos Tablas, Filas y Columnas, y en Mongo son Colecciones, Documentos y Claves.
- Los datos están estructurados, igual que un objeto JSON.
Si todavía no tiene Mongo, instálelo a través de su gestor de paquetes. En distribuciones basadas en Linux, por ejemplo:
1 |
$ sudo apt-get install mongodb |
Una
vez que tengamos instalado Mongodb, podemos añadir fácilmente soporte
Mongo a nuestra aplicación de chat con el módulo mongoose disponible
desde npm. Instale mongoose con lo siguiente:
1 |
$ npm install mongoose --save |
Ahora vamos a añadir un poco de Mongo a nuestra aplicación. Encienda su editor de código y abra app.js y configure la parte superior de su secuencia de comandos como sigue.
1 |
//Configure our Services
|
2 |
var PeerServer = require('peer').PeerServer, |
3 |
express = require('express'), |
4 |
mongoose = require('mongoose'), |
5 |
assert = require('assert'), |
6 |
events = require('./src/events.js'), |
7 |
app = express(), |
8 |
port = process.env.PORT || 3001; |
9 |
|
10 |
//Connect to the database
|
11 |
mongoose.connect('mongodb://localhost:27017/chat'); |
12 |
var db = mongoose.connection; |
13 |
|
14 |
mongoose.set('debug', true); |
15 |
|
16 |
db.on('error', console.error.bind(console, '# Mongo DB: connection error:')); |
Incluimos
mongoose con require('mongoose') y luego utilizamos nuestra conexión a
la base de datos a través de mongoose.connect('mongodb://localhost:27017/chat');.
El /chat define el nombre de la base de datos a la que nos estamos conectando.
A continuación, para propósitos de desarrollo, recomiendo que configuremos la depuración.
1 |
mongoose.set('debug', true); |
Finalmente agregamos un manejador para cualquier evento de error:
1 |
db.on('error', console.error.bind(console, '# Mongo DB: connection error:')); |
A continuación, puede agregar su chequeo de conexión con el código siguiente:
1 |
db.once('open', function (callback) { |
2 |
console.log("# Mongo DB: Connected to server"); |
3 |
}
|
La
forma en que se usa mongoose es que una vez que la instancia db
recibe el evento open, entraremos en ejecución para nuestra conexión
mongo. Así que tendremos que envolver nuestro código existente en esta nueva conexión mongo con el fin de utilizarlo.
Aquí está un listado de código completo con mongoose añadido e insertando filas y suprimiéndolos cuando los usuarios se conectan y se desconectan.
1 |
|
2 |
//Configure our Services
|
3 |
var PeerServer = require('peer').PeerServer, |
4 |
express = require('express'), |
5 |
mongoose = require('mongoose'), |
6 |
assert = require('assert'), |
7 |
events = require('./src/events.js'), |
8 |
app = express(), |
9 |
port = process.env.PORT || 3001; |
10 |
|
11 |
//Tell express to use the 'src' directory
|
12 |
app.use(express.static(__dirname + '/src')); |
13 |
|
14 |
//Connect to the database
|
15 |
mongoose.connect('mongodb://localhost:27017/chat'); |
16 |
var db = mongoose.connection; |
17 |
|
18 |
mongoose.set('debug', true); |
19 |
|
20 |
db.on('error', console.error.bind(console, '# Mongo DB: connection error:')); |
21 |
|
22 |
db.once('open', function (callback) { |
23 |
|
24 |
console.log("# Mongo DB: Connected to server"); |
25 |
|
26 |
//Setup our User Schema
|
27 |
var usersSchema = mongoose.Schema({username: String}); |
28 |
var User = mongoose.model('User', usersSchema); |
29 |
|
30 |
//Configure the http server and PeerJS Server
|
31 |
var expressServer = app.listen(port); |
32 |
var io = require('socket.io').listen(expressServer); |
33 |
var peer = new PeerServer({ port: 9000, path: '/chat' }); |
34 |
|
35 |
//Print some console output
|
36 |
console.log('#### -- Server Running -- ####'); |
37 |
console.log('# Express: Listening on port', port); |
38 |
|
39 |
peer.on('connection', function (id) { |
40 |
io.emit(events.CONNECT, id); |
41 |
console.log('# Connected: ', id); |
42 |
|
43 |
//Store Peer in database
|
44 |
var user = new User({ username: id }); |
45 |
user.save(function (err, user) { |
46 |
if (err) return console.error(err); |
47 |
console.log('# User '+ id + ' saved to database'); |
48 |
});
|
49 |
|
50 |
});
|
51 |
|
52 |
peer.on('disconnect', function (id) { |
53 |
io.emit(events.DISCONNECT, id); |
54 |
console.log('# Disconnected: ', id); |
55 |
|
56 |
//Remove Peer from database
|
57 |
User.remove({username: id}, function(err){ if(err) return console.error(err)}); |
58 |
|
59 |
});
|
60 |
|
61 |
});
|
Para ver esto funcionando, vamos a encender la aplicación de chat. Simplemente ejecute npm start para empezar
Ahora conéctese al chat normalmente dentro del navegador (por defecto en http://localhost:3001).
Una vez que te hayas conectado a tu chat, en una nueva ventana de terminal abra mongo chat para ingresar al mongo cli.
1 |
$ mongo chat
|
2 |
MongoDB shell version: 2.0.6 |
3 |
connecting to: chat |
4 |
> db.users.find() |
5 |
{ "username" : "CameronLovesPigs", "_id" : ObjectId("5636e9d7bd4533d610040730"), "__v" : 0 } |
Aquí
tienes el registro de documentos almacenado dentro de tu mongo, y ahora
siempre puedes comprobar cuántos usuarios están en línea ejecutándose
en el mongo prompt db.users.count().
1 |
> db.users.count() |
2 |
3 |
Cómo agregar sesiones a nuestra aplicación
Debido
a que hemos utilizado Express para construir nuestra aplicación, esta
parte es realmente bastante simple y sólo requiere la instalación de un
par de módulos de npm para marchar.
Obtenga los paquetes express-session y connect-mongo desde npm:
1 |
$ npm install express-session connect-mongo cookie-parser --save |
Ahora incluya en la parte superior de app.js:
1 |
var PeerServer = require('peer').PeerServer, |
2 |
cookieParser = require('cookie-parser'), |
3 |
express = require('express'), |
4 |
session = require('express-session'), |
5 |
mongoose = require('mongoose'), |
6 |
MongoStore = require('connect-mongo')(session), |
7 |
//...
|
Después de configurar mongoose.connect, puede configurar sesiones con express. Cambie su código a lo siguiente; Puede especificar su propia cadena secret.
1 |
//Connect to the database
|
2 |
mongoose.connect('mongodb://localhost:27017/chat'); |
3 |
var db = mongoose.connection; |
4 |
|
5 |
mongoose.set('debug', true); |
6 |
|
7 |
db.on('error', console.error.bind(console, '# Mongo DB: connection error:')); |
8 |
|
9 |
app.use(cookieParser()); |
10 |
app.use(session({ |
11 |
secret: 'supersecretstring12345!', |
12 |
saveUninitialized: true, |
13 |
resave: true, |
14 |
store: new MongoStore({ mongooseConnection: db }) |
15 |
}))
|
Aquí un punto crucial a destacar es el saveUninitialized: true dentro de la última app.use. Esto asegurará que las sesiones sean guardadas.
Especificamos
dónde con la propiedad store, que establecemos en la instancia
MongoStore, especificando qué conexión usar a través de
mongooseConnection y nuestro objeto db.
Para almacenar en la sesión, necesitamos usar express para el manejo de la solicitud porque necesitamos acceso al valor de la solicitud, por ejemplo:
1 |
//Start persistent session for user
|
2 |
app.use(function(req, res, next) { |
3 |
req.session.username = id; |
4 |
req.session.save(); |
Esto creará la variable req.session.username con el valor introducido por el usuario y lo guardará para más tarde.
A continuación, podemos comprobar este valor con nuestro código del cliente y registrar automáticamente el usuario cuando se actualizan para que nunca se desconecten del chat y se registren automáticamente como su nombre de usuario elegido.
También es interesante observar, porque tenemos sesiones respaldadas por la base de datos, es que en caso de que los desarrolladores cambien la aplicación y la recarga de back-end, los usuarios conectados a sus clientes permanecerán conectados como el almacén de sesión es ahora persistente. Esta es una gran característica para mantener a sus usuarios contentos y conectados durante todo el tiempo que se está desarrollando, o si hay una desconexión de un cliente inestable.
Ingreso persistente
Ahora que tenemos la parte de cookie de sesión configurada, vamos a trabajar en la adición de ingreso persistente a nuestro código de front-end.
Hasta ahora hemos utilizado la ruta predeterminada proporcionada por Express para una aplicación de SPA y no hemos definido ninguna ruta de manejo para Express. Como mencioné antes, para tener acceso a la sesión necesitará las variables de petición / respuesta de Express.
Primero
necesitamos una ruta para poder acceder al objeto request que
Express proporciona y mostrarlo para propósitos de depuración. Dentro
de su configuración Express en /app.js, agregue lo siguiente cerca de
la parte superior del archivo, después de la sesión de configuración:
1 |
app.use(session({ |
2 |
secret: 'supersecretstring12345!', |
3 |
saveUninitialized: true, |
4 |
resave: true, |
5 |
store: new MongoStore({ mongooseConnection: db }) |
6 |
}))
|
7 |
|
8 |
app.get('/', function (req, res) { |
9 |
res.sendFile(__dirname +'/src/index.html'); |
10 |
if(req.session.username == undefined){ |
11 |
console.log("# Username not set in session yet"); |
12 |
} else { |
13 |
console.log("# Username from session: "+ req.session.username); |
14 |
|
15 |
}
|
16 |
});
|
Ahora tenemos un registro básico para ver qué está pasando con nuestro valor de sesión. Para configurarlo, necesitamos configurar las rutas getter y setter de la siguiente manera:
1 |
//Save the username when the user posts the set username form
|
2 |
app.post('/username', function(req, res){ |
3 |
console.log("# Username set to "+ req.body.username); |
4 |
req.session.username = req.body.username; |
5 |
req.session.save(); |
6 |
console.log("# Session value set "+ req.session.username); |
7 |
res.end(); |
8 |
});
|
9 |
|
10 |
//Return the session value when the client checks
|
11 |
app.get('/username', function(req,res){ |
12 |
console.log("# Client Username check "+ req.session.username); |
13 |
res.json({username: req.session.username}) |
14 |
});
|
Estas dos rutas funcionarán como get y set para la sesión de username var. Ahora, con un poco de JavaScript básico, podemos implementar el inicio de sesión automático para nuestra aplicación. Abra src/App.js y cámbielo de la siguiente manera:
1 |
/* global EventEmitter, events, io, Peer */
|
2 |
/** @jsx React.DOM */
|
3 |
|
4 |
$(function () { |
5 |
'use strict'; |
6 |
|
7 |
// Check for session value
|
8 |
$(document).ready(function(){ |
9 |
$.ajax({ |
10 |
url: '/username' |
11 |
}).done(function (data) { |
12 |
console.log("data loaded: " + data.username); |
13 |
if(data.username) |
14 |
initChat($('#container')[0], data.username); |
15 |
});
|
16 |
});
|
17 |
|
18 |
// Set the session
|
19 |
$('#connect-btn').click(function(){ |
20 |
var data = JSON.stringify({username: $('#username-input').val()}); |
21 |
$.ajax({ url: '/username', |
22 |
method: "POST", |
23 |
data: data, |
24 |
contentType: 'application/json', |
25 |
dataType: 'json' |
26 |
});
|
27 |
});
|
28 |
|
29 |
// Initialize the chat
|
30 |
$('#connect-btn').click(function () { |
31 |
initChat($('#container')[0], |
32 |
$('#username-input').val()); |
33 |
});
|
34 |
|
35 |
function initChat(container, username) { |
36 |
var proxy = new ChatServer(); |
37 |
React.renderComponent(<ChatBox chatProxy={proxy} |
38 |
username={username}></ChatBox>, container); |
39 |
}
|
40 |
|
41 |
window.onbeforeunload = function () { |
42 |
return 'Are you sure you want to leave the chat?'; |
43 |
};
|
44 |
|
45 |
});
|
Con
la facilidad $.ajax de jQuery creamos una solicitud para comprobar el
valor de la variable de sesión cuando el document está disponible. Si
se establece, a continuación, inicializar nuestro componente React con
el valor almacenado, lo que resulta en una característica de autologin
para nuestros usuarios.
Encender el chat de nuevo con npm start y echar un vistazo en su navegador para ver las sesiones de trabajo.
Conclusiones
Ahora ha visto lo fácil que es utilizar Mongoose en conjunto con Express y configurar sesiones Express. Tomando su desarrollo de aplicaciones más con React como el controlador de vista vinculado a los elementos respaldados por la base de datos creará algunas aplicaciones serias.
Si desea dar un paso más con React y ver cómo sus componentes pueden comunicarse internamente dentro del marco React, esta guía de la documentación oficial es muy útil.



