【问题标题】:How to use Socket.io with Next.js API Routes如何将 Socket.io 与 Next.js API 路由一起使用
【发布时间】:2019-12-22 01:17:54
【问题描述】:

Next.js 提供serverless API routes。通过在./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>;
}

还有一个 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');
}

但我无法让客户端连接到 Socket.io 服务器并成功看到:'onconnection''connect''connection' 打印。

【问题讨论】:

标签: socket.io next.js


【解决方案1】:

诀窍是只将“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

./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>
}

【讨论】:

  • 如何与外部应用程序一起使用?假设我有一个连接到此 API 的移动应用程序,并且想要监听模型内的文档更改。例如,猫鼬post('save')
  • 此解决方案在开发中的一个问题是,在设置res.socket.server.io 之后,您无法利用该 if 语句中代码的热重载。
  • 我实际上只是将所有内容都切换到了 Pusher,因为 Vercel 在他们的 limitations docs 中说无服务器功能不支持 websockets。此外,他们有一个guide 来了解如何设置推送器。
  • 是的 pusher 确实使用 websockets,但是在与 pusher 交互时,您只是进行 REST API 调用。 POST 要具体。所有 websocket 的东西都在你的应用和推送器之间在客户端处理。
  • 1.您设置了一个无服务器函数,该函数使用 pusher /api/pusher/auth 2 进行身份验证。然后您的前端使用来自该密钥的密钥通过 pusher 3 对您的前端进行身份验证。我使用 use-pusher react hooks 来监听前端的事件。特别是useEventProvider 4. 我创建了诸如create-message 端点之类的端点,然后在创建消息+ 保存到db 之后,我使用了pusher.trigger('private-channel-name', 'message:created', message)
【解决方案2】:

您必须拥有/api/pusher/auth 才能通过前端推送器进行身份验证。然后,您使用从中获得的密钥与推送者进行通信。这是出于安全目的。您可以通过前端完成所有操作,但取决于您的应用,如果您要保存数据(例如消息或聊天),那么可能应该进行身份验证。

【讨论】:

  • 我们的身份验证方式是这样的:var pusher = new Pusher({ appId: '', key: '', secret: '', cluster: 'eu', encrypted: true });
  • 希望this gist 有所帮助。
  • 感谢您的回复 - 我已经做到了这一点,但我对 use-pusher 有一些问题,尤其是 usePresenceChannel,因为我想跟踪我的用户并将他们显示在聊天室中,但是可悲的是,存在渠道无法正常工作。你试过吗?它抛出了一些警告,因为没有使用 presenceChannel 的 auth 标头并且没有注册触发事件。我没有发现像你的要点这样的普通channel 有这个问题。
  • 您是否在 repo 中发布了问题?这是使用推动作者的问题。
  • 这是个好主意 - 我刚刚在这里:github.com/mayteio/use-pusher/issues/26。在您推荐该库之前,我正在考虑编写自己的实现以避免此类问题。它似乎写得很好,所以也许我做错了什么。你试过出席频道吗?您还会如何跟踪您的聊天室用户?
【解决方案3】:

您将需要创建一个单独的 express 服务器,然后在 IO 对象上,您必须配置 cors 以及配置要在 app 变量上使用的 cors。我有我在这里制作的示例套接字服务器作为与 Next.js 一起使用的答案。

const express = require("express");
const socket = require("socket.io");
const cors = require("cors");

const app = express();

app.use(cors());

const server = app.listen(process.env.PORT || 8080, () =>
  console.log("Port 8080")
);

// socket setup
const io = socket(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
    allowedHeaders: ["my-custom-header"],
    credentials: true
  }
});

io.on("connection", (socket) => {
  console.log("User connected");
  // socket event example send the specific data to the client
  socket.on("chat", (data) => {
    console.log(data);
    io.sockets.emit("chat", data);
  });
});

你可以看到我在哪里添加了 app.use(cors())

const io = socket(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST", "PATCH", "DELETE"],
    allowedHeaders: ["my-custom-header"],
    credentials: true
  }
});

您可以在这里找到更多信息https://socket.io/docs/v3/handling-cors

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2020-09-18
    • 2020-08-12
    • 2016-05-26
    • 2021-08-22
    相关资源
    最近更新 更多