reuse socket id on reconnect, socket.io, node.js

送分小仙女□ 提交于 2021-02-07 05:53:06

问题


is it possible to reuse a socket.id or use it multiple times?

Let's assume a user views multiple pages of the same site in different browser tabs. I want to use a single socket.id, socket to handle them all.

If a user receives a notification it should popup on all tabs with a single socket.emit.


回答1:


You can't reuse Socket.IO connection IDs since they are created during the client-server handshake, but there are alternative methods. I don't have any examples, but you can modify the Socket.IO client to pass along a query string when the handshake is being performed. Then you can tell the server to handle the client based on the query string, and later fetch all client IDs with a certain query string.

Another method you could use would be to use namespaces. Assuming you have some type of session system, you could create a session-specific namespace, and connect clients with that session ID straight to that namespace.




回答2:


It is possible

From the dates of previous responses I assume it might not have been possible in previous versions of socket.io, but I can confirm that I'm successfully reusing socket ids on reconnections with socket.io 2.3.0.

You just need to override io.engine.generateId. Whatever that method returns will be the id assigned to the socket. Here are the docs about generateId.

As far as I've experimented myself, there are two situations when that method is called. During connections and reconnections.

The method io.engine.generateId receives the originating request object as the argument, so we can use it to figure out if we want to reuse the id or get a fresh new one.

Example

As an example, I'll show how you would reuse an id sent from the client, or create a new one when the client doesn't send it. The id will be sent on the handshake request as the query param socketId.

1. Override io.engine.generateId

First you need to override io.engine.generateId, which is the method that assigns IDs. On the server you need to do something like this.

const url = require('url')
const base64id = require('base64id')

io.engine.generateId = req => {
  const parsedUrl = new url.parse(req.url)
  const prevId = parsedUrl.searchParams.get('socketId')
  // prevId is either a valid id or an empty string
  if (prevId) {
    return prevId
  }
  return base64id.generateId()
}

That way, whenever you send the query param socketId in the handshake request, it will be set as the socket id. If you don't send it you'll generate a new one using base64id. The reason to use that library in particular is because that's what the original method does. Here you can find the source code.

2. Send the information on the connection request

Once you have that, you need to send the socketId param from the client. This is described in the docs.

const socket = io.connect(process.env.WEBSOCKET_URL, {
  query: {
    socketId: existingSocketId || ''
  }
})

process.env.WEBSOCKET_URL would be the URL where your web socket is listening.

Note that this will work when connecting, but you might want to update the query on reconnection.

3. Send the information on the reconnection request

On the same section of the docs it explains how to update the query params before reconnection. You just need to do something like this.

socket.on('reconnect_attempt', () => {
  socket.io.opts.query = {
    socketId: existingSocketId || ''
  }
});

Just like that you'll be reusing the same socket id as long as it is sent from the client.

Security concerns

It's probably a bad idea to trust information sent from the client to assign the socket id. I'd recommend sending a cryptographically signed payload, storing that payload in the client, and send it back to the server when connecting and reconnecting. That way the server can check that the payload can be trusted by verifying the signature.

Using the same example above, we would send something like this to the client, maybe .on('connect'):

{
  socketId: 'foo',
  signature: SHA_256('foo' + VERY_SECRET_PASSWORD)
}

The client would store that payload and send it back on connecting or reconnecting, in the same way we were sending socketId before.

Once the server receives the signed payload, inside io.engine.generateId we could check that the signature in the payload matches the hash we produce using the ID and the VERY_SECRET_PASSWORD.




回答3:


Multiple sites?

No, that's not possible. It would be possible if you open those sites into iframes in your webapp, I guess.

Another option would be to build a browser plugin that opens a socket connection.



来源:https://stackoverflow.com/questions/18294620/reuse-socket-id-on-reconnect-socket-io-node-js

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