简体   繁体   English

刷新页面时Socket.io的多个连接

[英]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. 我正在使用实时应用程序,并且正在使用Socket.io来获取此功能。

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). 到目前为止,我所拥有的是,当用户发布某些内容(文本)时,我的套接字服务器会收到此消息,然后将其发送到我的控制器以将该数据保存在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. 每当刷新页面时都会发生这种情况,因此,如果刷新页面10次,我将在数据库中插入10条具有相同数据的消息。

This is the code I have right now, any help would be great. 这是我现在拥有的代码,任何帮助都将非常有用。

SocketServer.js 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 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) jQuery脚本(客户端)

$(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 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. 您没有显示足够多的代码来遵循整个流程,但是在我看来,您似乎在controllers.js文件中有重复的do-it消息事件处理程序。

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: 每次使用经过身份验证的请求调用controllers.js中的.index()方法时,您都会在此代码行中为do-it消息添加另一个事件处理程序:

 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. 看起来您不能在这里严格执行此操作,因为您还试图在同一代码中使用req 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. 我必须为controllers.js看到一个更大的代码上下文,以了解您实际上在尝试做什么以及解决问题的好选择。

FYI, what you've done here is mixed socket event handlers with http event handlers (put one event handler inside the other event handler). 仅供参考,您在这里所做的是将套接字事件处理程序与http事件处理程序混合使用(将一个事件处理程序放入另一个事件处理程序中)。 That pretty much never works as the two events happen at different times and you end up with duplicate handlers. 由于这两个事件在不同的时间发生,并且您最终得到重复的处理程序,因此几乎永远无法工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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