简体   繁体   中英

Is there a way to get the response for a specific emit using socket.io?

I need to perform GET requests on a server that doesn't have a CORS header, so I created a very simple node app that will do the GET for me:

var io = require('socket.io')();
var request = require('request');

io.on('connection', function(socket) {
  socket.on('get', function(url) {
    request(url, function(error, response, body) {
      socket.emit('response', body);
    });
  });
});

On the client side, I'm using it with a simple get function:

var socket = io();

function get(url) {
  return new Promise(function(resolve) {
    socket.emit('get', url);
    socket.once('response', function(data) {      
      resolve(data);
    });
  }
}

This works great when I request a URL one at a time:

get('http://some/resource/1');

But when I try multiple requests to different endpoints at the same time, they will all return the same data:

get('http://some/resource/1');
get('http://some/resource/2');
get('http://some/resource/3');

In this case, the data for /resource/1 is returned for all 3. I understand that this is because the socket.once('response') callback is getting added immediately for all 3 requests, and when the data is returned for the first one, all 3 callbacks are invoked for it.

Is there a way that I can get it so that each socket.emit() and socket.on() are paired to each other? I know that I can add a unique ID to each emit and pass it back on the response, or use the unique ID in the message itself (something like socket.emit('get:a54jk14hf') , but I'm hoping for a simpler solution if there is one.

The issue is that you are overwriting the socket.io's "response" event by issuing the "once" hook inside the "get" function. It's fine to keep it in there, but you'll need to provide a unique event for "once", that way four unique events will come back. This could be done using the "url" as key. It would look something like this:

Server:

var io = require('socket.io')();
var request = require('request');

io.on('connection', function(socket) {
  socket.on('get', function(url) {
    request(url, function(error, response, body) {
      socket.emit(
        'response-' + url, // USING THIS INSTEAD OF JUST "response"
        body
      );
    });
  });
});

Client:

var socket = io();

function get(url) {
  return new Promise(function(resolve) {
    socket.emit('get', url);
    socket.once(
      'response-' + url, // USING THIS INSTEAD OF JUST "response"
      function(data) {      
      resolve(data);
    });
  }
}

I'm not sure if this was a requirement of yours, but the above approach would also enable you to have the correct data always come back to the Promise's "then" block.

get('http://some/resource/1').then(function (data) {            
  // the "data" is now guaranteed to be from resource "1"
  // previous, it could have been from 1, 2, or 3 
})

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