socket.io |我应该将路由处理程序包装在 io.on('connection') 中吗?
Posted
技术标签:
【中文标题】socket.io |我应该将路由处理程序包装在 io.on(\'connection\') 中吗?【英文标题】:socket.io | Should I wrap my route handlers inside io.on('connection')?socket.io |我应该将路由处理程序包装在 io.on('connection') 中吗? 【发布时间】:2021-12-21 15:27:25 【问题描述】:在下面的代码中,我假设我的路由处理程序有可能会在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)
)
)
还是不建议这样做,有更好的选择?
【问题讨论】:
【参考方案1】:将app.post()
和app.get()
放在io.on('connection', ...)
中绝不是正确的设计或实现。这是因为io.on('connection', ...)
被多次触发,并且一遍又一遍地添加相同的快速路由处理程序没有意义,因为这只会浪费内存并且没有任何用处。第一个在 socket.io 上连接的客户端将导致路由被注册,并且从那时起,所有其他客户端(无论它们是否通过 socket.io 连接)都会在那里。
目前尚不清楚您为什么要这样做。您不会为一种特定情况安装路线。为所有州的所有客户端安装一次路由。因此,如果您尝试有条件地安装路由,那么这种类型的设计将不起作用。如果您进一步解释您要完成的工作,那么也许我们可以为设计提出一些不同的建议。
在下面的代码中,我假设我的路由处理程序有可能会在 io 连接建立之前触发并尝试发送到套接字:
app.post('/something', (req, res) =>
req.app.io.emit('something', doSomethingWith(req.body))
res.status(200)
);
此代码的具体工作方式取决于 POST 执行的操作。如果它是现有页面中的 javascript,那么该页面将已经启动并初始化,并且您可以控制(使用页面中的 Javascript 客户端代码)是否等待向/something
发出 POST 直到建立 socket.io 连接.
如果此 POST 是常规的基于浏览器的表单提交(不涉及 Javascript),那么您还有其他问题,因为来自浏览器的表单提交会使用 POST 的响应重新加载当前浏览器页面,并且在重新加载的过程中该页面会终止该页面具有的任何现有 socket.io 连接(因为它加载了一个新页面)。由于您没有从 POST 发回任何内容,这将导致浏览器中显示一个空白页面并且没有 socket.io 连接。
在查看您的客户端代码时,似乎 POST 来自客户端代码中的 fetch()
(因此完全基于 Javascript)。如果是这种情况,我建议重组您的客户端代码,以便它等到 socket.io 连接完成连接后再执行fetch()
。这样一来,您就知道您将能够收到服务器所做的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', ....)
);
【讨论】:
好的,所以基本上你的最后一段就是我问题的答案:)。我担心在建立套接字连接之前我的 fetch 可能会消失。所以根据你的建议,我假设socket.on('connect')
只会触发一次,对吗?
@SproutCoder - connect
事件在第一次连接时触发,然后如果连接因任何原因中断并且客户端自动重新连接,它将为此再次触发。如果你想确保 fetch()
只被调用一次,你可以为你是否已经调用过 fetch()
维护一个更高范围的标志,并在调用之前检查标志。
是的,我可能会使用一些 alreadyFired
布尔值之类的。谢谢你的解释!以上是关于socket.io |我应该将路由处理程序包装在 io.on('connection') 中吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 node.js 和 socket.io 应用程序中组织套接字处理
Socket.io 连接恢复为轮询,从不触发“连接”处理程序
是否可以将多个处理程序添加到同一个 socket.io.on 事件?
将 Node.js+Socket.io 包装成 OSX 可执行文件的可靠方法? (或用作替代品的 C/C++/Objective-C 库)