NextJS13.4.19 App Router中Socket.io服务搭建失败求助
问题分析与解决方案
你的问题核心在于NextJS 13.4.19 App Router的API路由规则与Pages Router完全不同,同时Socket.io在App Router下的挂载方式需要调整,导致出现404错误和多渲染器警告。以下是分步修复方案:
1. 调整Socket.io服务器挂载方式(使用自定义服务器)
App Router的API路由基于Web标准Request/Response,无法直接获取res.socket.server,因此推荐使用自定义服务器挂载Socket.io,这是最稳定的方案。
步骤1:创建自定义服务器文件
在项目根目录新建server.ts,内容如下:
import { createServer } from "http"; import { parse } from "url"; import next from "next"; import { Server } from "socket.io"; const dev = process.env.NODE_ENV !== "production"; const hostname = "localhost"; const port = 3000; // 初始化NextJS应用 const app = next({ dev, hostname, port }); const handle = app.getRequestHandler(); app.prepare().then(() => { const httpServer = createServer(async (req, res) => { try { const parsedUrl = parse(req.url!, true); await handle(req, res, parsedUrl); } catch (err) { console.error("请求处理失败", req.url, err); res.statusCode = 500; res.end("Internal Server Error"); } }); // 初始化Socket.io服务器 const io = new Server(httpServer, { path: "/api/socket/io", // 指定Socket.io路径,避免与NextJS路由冲突 cors: { origin: "http://localhost:3000", // 开发环境允许本地跨域 methods: ["GET", "POST"], }, }); // 监听Socket连接事件 io.on("connection", (socket) => { console.log(`客户端已连接: ${socket.id}`); // 监听客户端发送的input-change事件 socket.on("input-change", (msg) => { socket.broadcast.emit("update-input", msg); }); // 监听断开连接事件 socket.on("disconnect", () => { console.log(`客户端已断开: ${socket.id}`); }); }); // 启动服务器 httpServer.listen(port, () => { console.log(`> 服务已启动: http://${hostname}:${port}`); }); });
步骤2:修改package.json启动脚本
替换原有启动命令,使用自定义服务器启动项目:
{ "scripts": { "dev": "node server.ts", "build": "next build", "start": "NODE_ENV=production node server.ts" } }
2. 修复客户端组件代码
调整Socket.io初始化逻辑,匹配自定义服务器的配置:
'use client' import { FC, useState, useEffect } from 'react' import io from "socket.io-client"; import type { Socket } from 'socket.io-client' let socket: undefined | Socket export const DashboardMessagesPage: FC = () => { const [isContactInfoOpened, setIsContactInfoOpened] = useState(false); const [isRightSearchWidgetOpened, setIsRightSearchWidgetOpened] = useState(false); const [inputValue, setInputValue] = useState(''); // 用于接收同步的输入内容 useEffect(() => { // 初始化Socket连接 socket = io({ path: "/api/socket/io", // 与服务器端配置的路径一致 transports: ["websocket", "polling"], // 优先使用WebSocket传输 }) // 监听连接成功事件 socket.on('connect', () => { console.log('Socket连接成功') }) // 监听服务器推送的update-input事件 socket.on('update-input', (msg) => { setInputValue(msg) console.log('收到输入更新:', msg) }) // 组件卸载时断开Socket连接 return () => { socket?.disconnect() } }, []) // 示例:发送输入变化到服务器 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const value = e.target.value setInputValue(value) socket?.emit('input-change', value) } return ( <> {/* 你的原有页面内容 */} <div> <input type="text" value={inputValue} onChange={handleInputChange} placeholder="输入内容测试同步..." /> <p>同步内容: {inputValue}</p> </div> </> ) }
3. 清理旧文件
删除原来的app/api/socket.ts文件,因为现在使用自定义服务器挂载Socket.io,不再需要该文件。
4. 测试运行
执行npm run dev启动项目,打开两个浏览器窗口访问仪表盘页面,在一个窗口输入内容,另一个窗口应该能同步收到更新,控制台也会显示连接日志。
关于"多渲染器"警告
该警告通常是服务器组件与客户端组件的上下文冲突导致,使用自定义服务器后会自动消失。如果仍存在,需确保:
- 所有使用Socket.io的组件都添加了
'use client'指令 - 不在服务器组件中初始化Socket.io相关逻辑
内容的提问来源于stack exchange,提问作者Royal WebGuru
相关产品推荐
相关产品推荐

