socket.io |我应该将路由处理程序包装在 io.on('connection') 中吗?

socket.io | Should I wrap my route handlers inside io.on('connection')?

在下面的代码中,我假设我的路由处理程序有可能在 io 连接建立之前触发并尝试发送到套接字:

server.js:

import { Server } from 'socket.io'
....
....
const app = express()
const io = new Server(....)

app.io = io

app.post('/something', (req, res) => {
  req.app.io.emit('something', doSomethingWith(req.body))
  res.status(200)
})


io.on('connection', function(socket) {
  console.log('socket connected')

  socket.on('disconnect', (reason) => {
    console.log('disconnected due to = ', reason)
  })

})

client.js:

socket = io(`http://localhost:${port}`, { transports: ['websocket'] })

socket.on('something', (data) => {
  doSomethingMoreWith(data)
})

fetch('/something', ....)

在那种情况下,这样做是否更安全:

io.on('connection', function(socket) {
  app.post('/something', ....)
  app.get('/something', ....)
  .....
  ...

  socket.on('disconnect', (reason) => {
    console.log('disconnected due to = ', reason)
  })

})

或者不建议这样做,有更好的选择吗?

app.post()app.get() 放在 io.on('connection', ...) 中从来都不是正确的设计或实现。这是因为 io.on('connection', ...) 被多次触发,并且一遍又一遍地添加相同的快速路由处理程序毫无意义,因为这只会浪费内存并且无济于事。第一个连接到 socket.io 的客户端将导致路由被注册,并且从那时起它们将在那里用于所有其他客户端(无论他们是否通过 socket.io 连接)。

不清楚您为什么要这样做。您不会为一种特定情况安装路线。为所有州的所有客户安装一次路由。所以,如果你试图有条件地安装路由,那么这种设计是行不通的。如果你进一步解释你想要完成的事情,那么也许我们可以为设计提出一些不同的建议。

In the code below, I'm assuming there is a chance that my route handler will fire and try to emit to the socket before the io connection has been established:

app.post('/something', (req, res) => {
  req.app.io.emit('something', doSomethingWith(req.body))
  res.status(200)
});

此代码的具体工作方式取决于 POST 正在执行的操作。如果它是现有页面中的 Javascript,那么该页面将已经启动并初始化并且您可以控制(使用页面中的 Javascript 客户端代码)是否等待将 POST 发布到/something 直到建立 socket.io 连接之后。

如果此 POST 是常规的基于浏览器的表单提交(不涉及 Javascript),那么您还有其他问题,因为来自浏览器的表单提交会重新加载当前浏览器页面的响应从 POST 并在重新加载页面的过程中,终止该页面拥有的任何现有 socket.io 连接(因为它加载了新页面)。由于您没有从 POST 发回任何内容,这将导致浏览器中显示一个空白页面并且没有 socket.io 连接。

在查看您的客户端代码时,似乎 POST 可能来自客户端代码中的 fetch()(因此完全基于 Javascript)。如果是这种情况,我会建议重组您的客户端代码,以便它在执行 fetch() 之前等到 socket.io 连接完成连接。这样,您就知道您将能够收到服务器所提供的 io.emit()

socket = io(`http://localhost:${port}`, { transports: ['websocket'] })

socket.on('something', (data) => {
  doSomethingMoreWith(data)
});

socket.on('connect', () => {
   // only issue fetch after socket.io connection is operational
  fetch('/something', ....)
});