Socket.io double emits when executing express (v4) route

一个人想着一个人 提交于 2020-12-15 11:07:33

问题


I have a problem with double emits when executing express (v4) route.

Lets for example run bellow code. Request (pipe) and mkdir will start immediately (race condition) and there will be error, about that the folder does not exist (mkdir can't create it fast enough, before request is started and start to pipe the data). Cause of this error user is redirected to page X where he need to refill the form. NOW (after redirection with form refilling) everything is working (cause folder do exist on the time that data arrives, because it was created before - cause async operations MUST complete? - route execute the code at the "back" even if user is already redirected) BUT the emits are done twice - once for OLD data, and once for NEW data (duplicating part of the HTML page structure).

route in x.js file:

router.post('/Y', function(req, res) {
    request(opt, function(err, resp, body) {
        if (resp.statusCode === 200) {
            res.render('Y'); // so the emits can target something (they build html structure on page 'Y' with proper data)

            function socCon()
            {
                var room = '';
                return new Promise(function(resolve, reject)
                {
                    req.io.on('connection', function(socket)
                    {
                        room = 'room-' + socket.id;
                        socket.join(room);

                        if (socket.join(room)) {
                            resolve(room);
                        }
                        else {
                            reject(console.log('error'));
                        }
                    });
                });
            }
            socCon().then(data).catch(function(error)
            {
                console.log(error);
            });

            function data(room) {

                var myFolder = 'myFolder/';

                fs.mkdir(myFolder, {recursive : true}, function(err) {
                    if (err) {console.log(err);}
                });

                var file = fs.createWriteStream(myFolder + 'data.html', 'utf8');

                sio.emit('msg', {emit : emit}); // socket.io emits - with use of express route POST on page 'X'

            });
        }
        else {
            res.render('X', {ERRORS : ERRORS});
            res.end();
        }
    }).on('response', function(response) {
    }).pipe(file).on('error', function(err) {
        res.render('X', {ERRORS : ERRORS}); // we inform the user that he put wrong data in input field or that there is internal server error (whatever)
        res.end();
        // so we end 'Y' page connection here (but socket.io somehow collect all the data, emit it later on - when same route is hit again) and socket.sendBuffer does not work)
    });
)};

Is there any way to stop the old emits? I have tried socket.sendBuffer = []; (@jfreind00 suggestion at - socket.io stop re-emitting event after x seconds/first failed attempt to get a response) to no avail. Ideal would be to... stop whole request when there is redirection. But you can't stop async code from executing (or I just don't know how).

Client page Y:

<!DOCTYPE html>
<html>
<head>
    <title>TITLE</title>
</head>
<body>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
    socket.on('connect', function() {
        socket.sendBuffer = []; // does not work...
    });
    socket.on('msg', function(msg) {
        // some HTML mutation here
    });
</script>
</body>
</html>

Of course code is much more complicated, but this is enough (I think) to show the problem. This "application" is probably a bad design, but I don't know how to fix it.

index.js file (main "app" file):

var x = require('./routes/x.js');
var app = express();
app.use('/', x);
app.use(function(req, res, next) {
    req.io = io;
    next();
});
var io = require('socket.io')(server);

io.on('connection', function (soc) {
    soc.on('disconnect', function(reason) {
        console.log(reason);
    });
    // etc.
});

回答1:


This line of code:

req.io.on('connection', function(socket) {...});

Just adds a new duplicate event handler every time you run this route. So, after running the route twice, you have two event handlers for the connection event. After running that route three times, you have three event handlers for the connection event and so on. They just accumulate and never go away.

So, that explains the duplicate processing. You have duplicate event handlers so the same connection event is processed multiple times.

I can't really suggest a fix because I don't follow what you're trying to accomplish and this whole scheme of trying to catch the next connection event and assuming that belongs to a specific page is flawed (full of race condition issues) - not to mention that it adds a never ending set of duplicate event handlers. You will need one listener for the connection event that is outside any route handler and then use that incoming event to do whatever you want to do.



来源:https://stackoverflow.com/questions/62679013/socket-io-double-emits-when-executing-express-v4-route

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!