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

无法通过IPv4及Ngrok从本地主机外访问React+Node+Socket.IO应用

问题

跟着教程搭建了React+Node+Socket.IO简易应用,本地运行正常。但跨设备测试时出现问题:

  • 同一WiFi下的PC通过IPv4地址192.168.1.8:3000访问,能加载页面资源,但Socket功能完全失效
  • 移动设备通过Ngrok隧道访问,同样能加载页面,但无法收发消息

需求是让桌面PC作为服务器,实现不同设备间的客户端通信。代码复刻自教程仓库,使用的Ngrok命令为ngrok http 3000。

客户端代码(public/src/App.js)

import "./App.css";
import io from "socket.io-client";
import { useEffect, useState } from "react";

const socket = io.connect("http://localhost:3001");

function App() {
  //Room State
  const [room, setRoom] = useState("");

  // Messages States
  const [message, setMessage] = useState("");
  const [messageReceived, setMessageReceived] = useState("");

  const joinRoom = () => {
    if (room !== "") {
      socket.emit("join_room", room);
    }
  };

  const sendMessage = () => {
    socket.emit("send_message", { message, room });
  };

  useEffect(() => {
    socket.on("receive_message", (data) => {
      setMessageReceived(data.message);
    });
  }, [socket]);
  return (
    <div className="App">
      <input
        placeholder="Room Number..."
        onChange={(event) => {
          setRoom(event.target.value);
        }}
      />
      <button onClick={joinRoom}> Join Room</button>
      <input
        placeholder="Message..."
        onChange={(event) => {
          setMessage(event.target.value);
        }}
      />
      <button onClick={sendMessage}> Send Message</button>
      <h1> Message:</h1>
      {messageReceived}
    </div>
  );
}

export default App;

服务器代码(server/index.js)

const express = require("express");
const app = express();
const http = require("http");
const { Server } = require("socket.io");
const cors = require("cors");

app.use(cors());

const server = http.createServer(app);

const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

io.on("connection", (socket) => {
  console.log(`User Connected: ${socket.id}`);

  socket.on("join_room", (data) => {
    socket.join(data);
  });

  socket.on("send_message", (data) => {
    socket.to(data.room).emit("receive_message", data);
  });
});

server.listen(3001, () => {
  console.log("SERVER IS RUNNING");
});
解决方案

1. 修改客户端Socket连接地址(核心问题)

硬编码的http://localhost:3001仅在本地有效,其他设备无法通过这个地址访问桌面PC的Socket服务器。改成动态适配当前访问环境的地址:

// 替换原来的io.connect("http://localhost:3001")
const socket = io.connect(`${window.location.protocol}//${window.location.hostname}:3001`);

这样不管是用本地IPv4(192.168.1.8:3000)还是Ngrok地址访问客户端,Socket都会自动连接到对应主机的3001端口。

如果移动设备通过Ngrok访问,需要给Socket服务器的3001端口单独开隧道:

ngrok http 3001

然后将客户端的Socket连接地址替换为Ngrok生成的地址,比如:

const socket = io.connect("https://abc123.ngrok.io");

2. 放宽服务器CORS限制

原来的CORS配置仅允许http://localhost:3000的请求,其他设备的访问会被拦截。修改服务器的Socket.IO CORS配置:

const io = new Server(server, {
  cors: {
    origin: "*", // 开发环境可使用通配符,生产环境建议指定具体允许的域名/IP
    methods: ["GET", "POST"],
  },
});

3. 验证服务器监听设置

默认server.listen(3001)已经监听所有网络接口(0.0.0.0),无需额外修改,确保桌面PC的IPv4地址能被同一WiFi下的设备访问即可。

测试步骤

  1. 重启Node服务器和React开发服务器
  2. 同一WiFi下的PC:访问http://192.168.1.8:3000,输入房间号并发送消息
  3. 移动设备:如果用Ngrok,先执行ngrok http 3000获取客户端地址,再执行ngrok http 3001获取Socket地址(或用动态适配的代码),访问客户端地址后加入同一房间测试消息收发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:15:30