简体   繁体   中英

Socket.io multiple connections when refreshing page

I'm working in a real-time app, and I'm using Socket.io to get this feature.

What I have so far is, when a user post something (text), my sockets server receive this message and then it sends to my controller to save this data on a DB (MySQL). Then the same message is returned to the client through the same socket server.

Actually this works well, but when I refresh my browser and post a new message, the data is inserted twice in the database, so I receive the same two messages in my client. This happens everytime that I refresh the page, so if I've refreshed the page 10 times, I will insert 10 messages with the same data on my DB.

This is the code I have right now, any help would be great.

SocketServer.js

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);

//websockets
var messages = 'Recibido';
var Usuarios = 0;
var storeUsers = [];

app.use(express.static('public'));

io.sockets.on('connection', function(socket) {
  Usuarios++;

  console.log('Usuarios totales: ' + Usuarios);
  io.sockets.emit('users-connected', Usuarios);

  var clients = io.sockets.clients();
  var conectados = clients.connected;

  console.log('------------------ROOM-------------------------');
  for (client in conectados) {
    var color = '\x1b[32m' + client;
    console.log('id: ' + color, '\x1b[0m');
  }
  console.log('\x1b[0m', '-----------------------------------------------');

  socket.on('disconnect', function() {
    Usuarios--;
    var desconectao = '\x1b[31m' + socket.id
    console.log('Socket desconectado: ' + desconectao, '\x1b[0m');
    io.sockets.emit('users-connected', Usuarios);
    socket.removeAllListeners();
  });

  socket.on('new-publication', function(data){
    console.log('Mensaje del usuario: ' + data.pub);
    io.sockets.emit('do-it', data)
  })

  socket.on('do-publication', function(data){

    console.log('Info: ' + data.nombre);
    io.sockets.emit('do-publication', data)
  })

});

http.listen(8081, function() {
  console.log("websockets corriendo en el puerto 8081");
});

Controller.js

var mysql = require('mysql');
var io = require('socket.io-client');
var socket = io.connect('http://localhost:8081', {transports: ['websocket'], upgrade: false});


module.exports = {

    index: function(req,res,next){

        if (req.isAuthenticated()) {

            var config =require('.././database/config');
            var db = mysql.createConnection(config);

            db.query('SELECT publicaciones.publicacion, publicaciones.fecha_pub, publicaciones.imagen ,users.nombre AS nombre, users.image AS image FROM publicaciones JOIN users ON publicaciones.id_user = users.id ORDER BY fecha_pub DESC', function(err, rows, fields){

                resultado    = rows;

                var message = {
                    isAuthenticated : req.isAuthenticated(),
                    items: resultado,
                    user: req.user,
                };

                res.render('users/panel',message);

            });

            socket.on('users-connected', function(data){
                console.log('Conectado al servidor Websockets');
                console.log('Usuarios conectados: ' + data);
            });

            socket.on('do-it', function(data){
                var datos_pub;
                console.log(data.pub);
                var currentdate = new Date();
                var datetime = currentdate.getFullYear() + "-"
                + (currentdate.getMonth()+1) + "-"
                + currentdate.getDate() + " "
                + currentdate.getHours() + ":"
                + currentdate.getMinutes() + ":"
                + currentdate.getSeconds();

                var publicacion = {
                    id_user : req.user.id,
                    publicacion : data.pub,
                    imagen : null,
                    fecha_pub : datetime
                };

                function loadSelect(id) {

                    var resultado = {};
                    db.query('SELECT publicaciones.publicacion, publicaciones.fecha_pub, users.nombre AS nombre, users.image AS image FROM publicaciones JOIN users ON publicaciones.id_user = users.id where id_publicacion=' + id, function(err, rows, fields){


                        socket.emit('do-publication', {
                            nombre: rows[0].nombre,
                            publicacion: rows[0].publicacion,
                            fecha: rows[0].fecha_pub,
                            image: rows[0].image
                        });
                    });
                }

                db.query('INSERT INTO publicaciones SET ?', publicacion, function(err, rows, fields){
                    if(err) throw err;
                    //db.end();
                    datos_pub =  rows.insertId;
                    loadSelect(datos_pub);

                });
          });

        }else{

                res.render('users/signin',{
                    isAuthenticated : req.isAuthenticated(),
                    user : req.user,
                    publicacion : req.publicacion,
                    messages : req.flash('info')
                });
        }
    }
}

Jquery Script (Client Side)

$(document).ready(function(){

  var socket = io.connect('http://localhost:8081', {transports: ['websocket'], upgrade: false});

  socket.on('do-publication', function(data){
    console.log(data.image);
    var imageprofile = "http://localhost:3000/images/upload_images/"+data.image;
    var $items = $('<div id="card-container" class="grid-item"><div class="card"><img class="avatar" src="'+imageprofile+'"><div class="name">'+data.nombre+'</div><div class="date">'+data.fecha+ '</div><p class="card">'+data.publicacion+'</p></div></div>');
    $grid.prepend( $items )
    .masonry( 'prepended', $items );
  })

  socket.on('users-connected', function(data){
    console.log('Usuarios conectados: ' + data);
  })

  $('#Button-Post-Publication').click(function(e){
    e.preventDefault();
    var publication = $('#Text-Area-Publication').val();    
    socket.emit('new-publication', {pub: publication})


  })
})

Updated with Passport and Middleware

Passport.js

var LocalStrategy = require('passport-local').Strategy;
var mysql= require('mysql');
var bcrypt = require('bcryptjs');

module.exports = function(passport){

    passport.serializeUser(function(user, done){
        done(null, user);
    });

    passport.deserializeUser(function(obj,done){
        done(null,obj);
    });

    passport.use(new LocalStrategy({
        passReqToCallback: true

    }, function(req,email,password,done){

        var config = require('.././database/config');

        var db = mysql.createConnection(config);
        db.connect();

        db.query('SELECT * FROM users WHERE email = ?',email, function(err,rows,fields){
            if(err) throw err;
            db.end();
            if(rows.length > 0){

                var user = rows[0];
                if (bcrypt.compareSync(password,user.password)) {
                    return done (null,{
                        id: user.id,
                        nombre: user.nombre,
                        email: user.email,
                        image : user.image
                    });
                }
            }

            return done(null,false, req.flash('authmessage','Email o Password incorrecto'));
        });


    }
    ));

};

Middleware

module.exports ={
    isLogged:function(req,res,next){
        // si esta autentificado continua en caso contrario ira a la página de registro
        if(req.isAuthenticated()){
            next();
        }else{
            res.redirect('/');
        }
    }
}

A page refresh kills the socket connection and creates a new one. This will happen with network outages or anything else that will break the connection.

You don't show enough of your code to follow the whole flow, but it looks to me like you may have duplicate event handlers for the do-it message in your controllers.js file.

Each time the .index() method in controllers.js is called with an authenticated request, you will add another event handler for the do-it message in this line of code:

 socket.on('do-it', function(data){...});

That will cause you to process that message multiple times, each time it arrives, leading to duplicate database inserts.

So, you aren't actually getting duplicate messages, you are just getting the message once for a given piece of data as intended, but you have duplicate event handlers installed which each processes the message.

Usually, the answer to a problem like this is move the event handlers out of the code that happens more than once so the event handlers are only ever added once during your code initialization. It doesn't look like you can strictly do that here because you're also trying to use req in the same code. I'd have to see a greater code context for controllers.js to understand what you're actually trying to do and what a good option would be for solving.

FYI, what you've done here is mixed socket event handlers with http event handlers (put one event handler inside the other event handler). That pretty much never works as the two events happen at different times and you end up with duplicate handlers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM