如何将 Socket.io 与 Next.js API 路由一起使用

Aur*_*ius 22 socket.io next.js

Next.js 提供无服务器 API 路由。通过在./pages/api你下面创建一个文件可以让你的服务运行,我想通过使用这种机制来拥有一个 Socket.io 服务。

我创建了一个客户端:

./pages/client.js

import { useEffect } from 'react';
import io from 'socket.io-client';

export default () => {

  useEffect(() => {
    io('http://localhost:3000', { path: '/api/filename' });
  }, []);

  return <h1>Socket.io</h1>;
}
Run Code Online (Sandbox Code Playgroud)

还有一个 API 路由:

./pages/api/filename.js

const io = require('socket.io')({ path: '/api/filename' });

io.onconnection = () => {
  console.log('onconnection');
}

io.on('connect', () => {
  console.log('connect');
})

io.on('connection', () => {
  console.log('connection');
})

export default (req, res) => {
  console.log('endpoint');
}
Run Code Online (Sandbox Code Playgroud)

但我不能让客户端连接到服务器Socket.io成功地和看不到任何的:'onconnection''connect''connection'打印。

rog*_*lle 21

诀窍是将“socket.io”插入http服务器一次,因此检查对api的每次访问。尝试这样的事情:

./pages/api/socketio.js

import { Server } from 'socket.io'

const ioHandler = (req, res) => {
  if (!res.socket.server.io) {
    console.log('*First use, starting socket.io')

    const io = new Server(res.socket.server)

    io.on('connection', socket => {
      socket.broadcast.emit('a user connected')
      socket.on('hello', msg => {
        socket.emit('hello', 'world!')
      })
    })

    res.socket.server.io = io
  } else {
    console.log('socket.io already running')
  }
  res.end()
}

export const config = {
  api: {
    bodyParser: false
  }
}

export default ioHandler
Run Code Online (Sandbox Code Playgroud)

./pages/socketio.jsx

import { useEffect } from 'react'
import io from 'socket.io-client'

export default () => {
  useEffect(() => {
    fetch('/api/socketio').finally(() => {
      const socket = io()

      socket.on('connect', () => {
        console.log('connect')
        socket.emit('hello')
      })

      socket.on('hello', data => {
        console.log('hello', data)
      })

      socket.on('a user connected', () => {
        console.log('a user connected')
      })

      socket.on('disconnect', () => {
        console.log('disconnect')
      })
    })
  }, []) // Added [] as useEffect filter so it will be executed only once, when component is mounted

  return <h1>Socket.io</h1>
}
Run Code Online (Sandbox Code Playgroud)

  • 开发中此解决方案的一个问题是,设置“res.socket.server.io”后,您无法利用 if 语句内的代码热重载。 (4认同)
  • 实际上,我只是将所有内容都切换到 Pusher,因为 Vercel 在他们的[限制文档](https://vercel.com/docs/platform/limits#websockets) 中表示,无服务器功能不支持 websockets。此外,他们还有一个关于如何设置推送器的[指南](https://vercel.com/guides/deploying-pusher-channels-with-vercel)。 (4认同)
  • @rogeriojlle我试图理解这个 res.socket.server 属性是什么。我正在使用 Typescript,它抱怨套接字属性上不存在服务器。我尝试使用 NextApiResponse 类型,但仍然出现相同的错误。有关于此套接字和服务器属性的任何文档吗?谢谢! (3认同)
  • 是的,pusher 确实使用了 websocket,但是当与 Pusher 交互时,您仅进行 REST API 调用。帖子要具体。所有 websocket 内容都在您的应用程序和推送器之间的客户端处理。 (2认同)
  • 1. 您设置一个使用 Pusher `/api/pusher/auth` 进行身份验证的无服务器函数 2. 然后您的前端使用其中的密钥通过 Pusher 来验证您的前端 3. 我使用了 [use-pusher](https://github .com/mayteio/use-pusher)用于监听前端事件的反应钩子。具体来说是 `useEvent` 和 `Provider` 4. 我创建了端点,例如创建消息端点,然后在创建消息并保存到数据库后,我使用了 `pusher.trigger('private-channel-name', 'message:创建',消息)` (2认同)
  • 当服务器启动时,我收到 404 错误,这意味着 /socket.io 不存在,但仅限于我的最新项目,该项目使用较新版本的 NextJS。这是令人难以置信的令人沮丧。 (2认同)