You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Next.js中Socket.io在服务端和客户端重复实例化

Next.js 14 + Socket.IO 双连接问题解决指南

环境配置

  • 客户端:Next.js 14
  • 服务端:Express
  • WebSocket框架:socket.io

核心代码

服务端(index.ts)

import * as socket from "socket.io";
import express from "express";
import http from "http";
import cors from "cors";

const app = express();
app.use(cors());

const server = http.createServer(app);

const io = new socket.Server(server, {
  cors: {
    origin: true,
  },
});

io.on("connection", async (socket) => {
  console.log(`Connection established`, socket.id);

  socket.on("disconnect", () => {
    console.log("user disconnected", socket.id);
  });

  socket.on("chat-message", (text) => {
    console.log(text);
    socket.broadcast.emit("chat-message", text);
  });
});

server.listen(4000, () => {
  console.log("Server running on http://localhost:4000");
});

客户端相关文件

1. app/lib/socket.ts

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

const url = 'http://localhost:4000';
console.log(`initialize socket`); 
export const socket = io(url);

2. app/page.tsx(已添加"use client"指令)

问题现象

首次访问localhost:3000时,Socket会在服务端和客户端各初始化一次,服务端收到两次连接请求;后续新浏览器窗口访问时仅客户端初始化一次Socket,符合预期。

疑问解答

1. 为什么代码会在服务端和客户端各执行一次?

Next.js 14的App Router默认以**服务端组件(Server Components)**为核心渲染模式,服务端组件会在服务器上执行并生成HTML返回给客户端。即便你在page.tsx中添加了"use client",如果socket.ts没有被限制为仅客户端执行,服务端渲染page.tsx时会同步加载并执行socket.ts里的代码(包括创建Socket连接);当客户端拿到HTML后,又会执行客户端组件内的代码,再次创建Socket连接,最终导致双连接。

2. 如何阻止服务端执行该代码,仅在客户端初始化Socket?

有两种实用方案:

方案一:用环境判断包裹Socket创建逻辑

修改socket.ts,仅在浏览器环境(存在window对象)时初始化Socket:

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

let socket: ReturnType<typeof io> | null = null;

export const getSocket = () => {
  // 仅在客户端环境初始化Socket
  if (typeof window !== 'undefined' && !socket) {
    console.log(`initialize socket`);
    socket = io('http://localhost:4000');
  }
  return socket;
};

后续在客户端组件中调用getSocket()获取实例即可,服务端渲染时不会执行初始化逻辑。

方案二:将socket.ts标记为客户端组件

在socket.ts顶部添加"use client"指令,强制Next.js将其视为客户端组件,服务端渲染时不会执行其中代码:

"use client";
import { io } from 'socket.io-client';

const url = 'http://localhost:4000';
console.log(`initialize socket`); 
export const socket = io(url);

内容的提问来源于stack exchange,提问作者nburk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:05:13