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

Next.js 13 App Router集成Socket.io遇404错误求助

Next.js 13 App Router 中 Socket.io 404 错误解决方法

问题重现

基于Pages Router的Socket.io示例,在Next.js 13 App Router的api/socket/route.ts中实现时,出现以下404错误:

polling.js:298 GET http://localhost:3000/socket.io?EIO=4&transport=polling&t=OkUN45A 404 (Not Found)

错误原因

App Router与Pages Router的API路由机制存在差异,用户代码存在以下问题:

  1. 参数错误:App Router的GET函数参数为request和context,而非Pages Router的req/res,无法直接通过res.socket获取服务器实例。
  2. 返回值错误:直接返回NextResponse类而非实例,未正确结束请求。
  3. 路径不匹配:Socket.io客户端默认请求/socket.io,但服务器配置的路径为/api/socket,且未在客户端指定对应路径。

修复步骤及完整代码

1. 类型定义(可选)

在app/types/next.ts中添加类型声明,方便类型提示:

import { Server as NetServer } from "http";
import { Server as ServerIO } from "socket.io";

export type ExtendedServer = NetServer & {
  io?: ServerIO;
};

2. 修复后的app/api/socket/route.ts

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { Server as ServerIO } from "socket.io";
import type { ExtendedServer } from "@/app/types/next";

export const config = {
  api: {
    bodyParser: false, // 必须关闭,避免Socket.io请求被错误解析
  },
};

export async function GET(request: NextRequest) {
  const server = request.socket.server as ExtendedServer;

  // 仅初始化一次Socket.io服务器
  if (!server.io) {
    console.log("初始化新Socket.io服务器");
    const io = new ServerIO(server, {
      path: "/api/socket", // 自定义Socket.io路径
      addTrailingSlash: false,
    });

    // 添加Socket.io事件监听示例
    io.on("connection", (socket) => {
      console.log(`客户端连接:${socket.id}`);

      socket.on("message", (data) => {
        io.emit("message", data); // 广播消息给所有客户端
      });

      socket.on("disconnect", () => {
        console.log(`客户端断开:${socket.id}`);
      });
    });

    server.io = io;
  }

  return NextResponse.json({}, { status: 200 }); // 返回空响应结束请求
}

3. 客户端连接代码(客户端组件)

必须在客户端组件中使用Socket.io,确保路径与服务器配置一致:

"use client";

import { useEffect, useState } from "react";
import { io, Socket } from "socket.io-client";

export default function ChatComponent() {
  const [socket, setSocket] = useState<Socket | null>(null);
  const [inputMsg, setInputMsg] = useState("");
  const [messageList, setMessageList] = useState<string[]>([]);

  useEffect(() => {
    // 连接时指定服务器配置的路径
    const newSocket = io(window.location.origin, {
      path: "/api/socket",
    });

    newSocket.on("message", (msg) => {
      setMessageList(prev => [...prev, msg]);
    });

    setSocket(newSocket);

    return () => newSocket.close();
  }, []);

  const sendMessage = () => {
    if (socket && inputMsg.trim()) {
      socket.emit("message", inputMsg);
      setInputMsg("");
    }
  };

  return (
    <div className="chat-container">
      <div className="messages">
        {messageList.map((msg, idx) => (
          <div key={idx} className="message">{msg}</div>
        ))}
      </div>
      <div className="input-area">
        <input
          type="text"
          value={inputMsg}
          onChange={(e) => setInputMsg(e.target.value)}
          placeholder="输入消息..."
        />
        <button onClick={sendMessage}>发送</button>
      </div>
    </div>
  );
}

关键注意事项

  • 必须关闭bodyParser:Socket.io使用自定义的请求格式,开启bodyParser会导致请求解析失败。
  • 路径一致性:服务器配置的path必须和客户端连接时指定的path完全一致,否则会触发404。
  • 服务器单例:确保Socket.io服务器只初始化一次,避免重复创建实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:06:29