如何在Deno服务器的同一端口上处理HTTP和WebSocket连接?

xbp102n0  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(173)

我决定使用Deno来开发一个非常小的服务器,它将通过HTTP向客户端提供最小的页面,并继续通过WebSockets与客户端通信。
我还没有在网上找到任何关于使用Deno通过单个端口提供HTTP和WebSocket的材料(至少没有使用一些第三方库,我还没有检查过这些),所以我试图自己提出一个解决方案,但遇到了一个奇怪的问题。
以下是我目前为止的代码:

// Accept TCP connections over port 8080
for await (const connection of Deno.listen({ port: 8080 })) {
  // Process all the arriving requests
  for await (const requestEvent of Deno.serveHttp(connection)) {
    // Check for the presence of an upgrade header
    if (requestEvent.request.headers.get('upgrade') === 'websocket') {
      // Provide a WebSocket connection
      const { socket, response } = Deno.upgradeWebSocket(requestEvent.request)
      socket.addEventListener('message', e => { console.log(e.data) })
      requestEvent.respondWith(response)
    } else {
      // Otherwise just respond normally
      requestEvent.respondWith(new Response('Hello!'))
    }
  }
}

字符串
当我运行这个时,我得到的奇怪行为是,我最初可以通过任何一种协议进行连接,但是一旦我与普通HTTP客户端连接,我就不能再创建新的WebSocket连接。相反的方式工作得很好。

amrnrhlw

amrnrhlw1#

实际上,我已经设法弄清楚了这一点,同时尽量减少我在这里演示的可重复示例,但我认为我仍然会发布它,因为它也可能是其他人的有用资源。
所以,我的代码的问题是,除了WebSocket消息的处理之外,我几乎所有的东西都是同步的。这会导致循环停留在为单个HTTP连接服务,并阻止它处理其他连接及其请求。当然,如果我尝试从另一个设备连接,这也不起作用。
为了解决这个问题,我只需要做一个小小的调整,通过将每个连接 Package 在一个 * 立即调用的异步箭头函数 * 中,为每个连接提供自己的事件处理程序循环:

// Accept TCP connections over port 8080
for await (const connection of Deno.listen({ port: 8080 })) {
  // Split off a dedicated asynchronous loop
  (async () => {
    // Process all the arriving requests
    for await (const requestEvent of Deno.serveHttp(connection)) {
      // Check for the presence of an upgrade header
      if (requestEvent.request.headers.get('upgrade') === 'websocket') {
        // Provide a WebSocket connection
        const { socket, response } = Deno.upgradeWebSocket(requestEvent.request)
        socket.addEventListener('message', e => { console.log(e.data) })
        requestEvent.respondWith(response)
      } else {
        // Otherwise just respond normally
        requestEvent.respondWith(new Response('Hello!'))
      }
    }
  })()
}

字符串
ps.:也许在监听器上循环使用.accept().then(<connection handling code here>)对某些人来说更易读,我想这有点主观。

相关问题