为后续“web 终端”功能做前置准备。需要 WebSocket 的支持。

Next.js 创建 WebSocket 需要使用 pages router。app router 没有完整的 request 与 response 对象。

这里使用 socket.io 在 Next.js 服务端口上支持 WebSocket。

socket.io-client 作为客户端对接 WebSocket 服务。

开发

安装依赖

pnpm i socket.io socket.io-client

创建一个 pages 的 api routes

pages/api/hello.ts

import { Server as NetServer } from 'http'
import { NextApiRequest } from 'next'
import { Server as ServerIO } from 'socket.io'
import { NextApiResponseServerIO } from '@/pages/api/types'

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

const ioHandler = (req: NextApiRequest, res: NextApiResponseServerIO) => {
  if (!res.socket.server.io) {
    const path = '/api/hello'
    const http_server: NetServer = res.socket.server as any
    const io = new ServerIO(http_server, {
      path: path,
      addTrailingSlash: false,
    })

    io.on('connection', (socket) => {
      socket.on('message', (msg) => {
        socket.emit('message', `server res: ${msg}`)
      })

      socket.on('disconnect', () => {
        console.log('A user disconnected', socket.id)
        socket.broadcast.emit('user server disconnection', socket.id)
      })
    })

    res.socket.server.io = io
  }

  res.end()
}

export default ioHandler

这样使用 socket.io 就创建好了一个简单的 socket 服务

TypeScript 类型描述文件

page/api/types.ts

import { Server as NetServer, Socket } from 'net'
import { NextApiResponse } from 'next'
import { Server as SocketIoServer } from 'socket.io'

export type NextApiResponseServerIO = NextApiResponse & {
  socket: Socket & { server: NetServer & { io: SocketIoServer } }
}

客户端,创建一个临时的对接页面

app/test-socket/page.tsx

'use client'
import React, { useRef, useState } from 'react'
import { useMount } from 'ahooks'
import { io, Socket } from 'socket.io-client'
import { Button } from 'antd'

const TestSocket: React.FC = () => {
  const [message, changeMessage] = useState<string[]>([])
  const socket_ref = useRef<Socket>()

  useMount(() => {
    const s_io = io({ path: '/api/hello', addTrailingSlash: true })

    socket_ref.current = s_io

    s_io.on('message', (msg) => {
      changeMessage((message) => {
        return [msg, ...message]
      })
    })
  })

  return (
    <>
      <Button
        onClick={() => {
          socket_ref.current?.emit('message', Date.now())
        }}
      >
        发送
      </Button>
      <ul>
        {message.map((text, key) => (
          <li key={key}>{text}</li>
        ))}
      </ul>
    </>
  )
}

export default TestSocket

每次点击“发送”按钮会将当前时间戳发送给 WebSocket,WebSocket 原封不动的将时间戳返回,并带上 server res 的前缀。

到此,Next.js 简单的实现了 WebSocket。

效果

git-repo

yangWs29/share-explorer


寒露
18 声望0 粉丝