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

Google Cloud上Node+Express+Socket.io服务的WebSocket连接失败问题

Google Cloud上Node+Express+Socket.io WebSocket连接被拒问题解决指南

问题场景

页面可正常加载,但WebSocket连接被立即拒绝,怀疑是环境配置或依赖问题导致。

相关代码

server.js

const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const fs = require("fs");

async function getCount() {
    return new Promise((resolve, reject) => {
        fs.readFile("count.json", (err, data) => {
        if (err) {
            reject(err);
        } else {
            const count = JSON.parse(data).count;
            resolve(count);
        }
        });
    });
}

async function writeCount(count) {
    const data = {
        count: count
    };

    return new Promise((resolve, reject) => {
        fs.writeFile("count.json", JSON.stringify(data), (err) => {
        if (err) {
            reject(err);
        } else {
            resolve();
        }
        });
    });
}


app.use(express.static("public"));

io.on("connection", (socket) => {
    socket.on("error", console.error);

    getCount().then(count => {
        io.emit("init", count);
    }).catch(err => {
        console.log(err);
    })

    socket.on("serversync", (receivedSync) => {
        console.log("received " + receivedSync);
        if (receivedSync >= 120) {
            console.log("not using " + receivedSync);
            return;
        }
        
        getCount().then(count => {
            let total = count + parseInt(receivedSync);
            io.emit("clientsync", total);
            writeCount(total);
        }).catch(err => {
            console.log(err);
        })
    });
});

app.get("/init", (req, res) => {
    let files = fs.readdirSync("./public/audio");
    res.json([files]);
})

const PORT = process.env.PORT || 8080;

server.listen(PORT, () => {
    console.log(`Listening on port ${PORT}.`);
});

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Kalam:wght@700&display=swap" rel="stylesheet">
    <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
    <link rel="stylesheet" href="css/index.css">
  </head>
  <body class="center">
    <div>
      <h1 id="global"></h1>
      <h2 id="globalText">Global Pikas</h2>
    </div>

    <div>
      <img id="buttonImg" src="images/button.gif" alt="Pika" onclick="onClick()">
    </div>  

    <div id="counterDiv">
      <h3 id="counter">0</h3>
      <h4 id="counterText">Times Pika'd</h4>
    </div>

    <script src="js/index.js"></script>
    <script src="js/animator.js"></script>
  </body>
</html>

报错截图

WebSocket连接被拒绝


排查与解决步骤

  1. 版本兼容性校验
    前端用的是4.5.4版本的Socket.io CDN,后端必须安装同大版本的socket.io包,执行命令:

    npm install socket.io@4.x
    

    版本不匹配是WebSocket连接失败的常见原因,无需本地下载替换CDN,只要前后端版本兼容即可。

  2. Google Cloud环境配置调整

    • 端口与绑定地址:代码中server.listen(PORT)默认绑定0.0.0.0,符合Google Cloud要求,无需修改;端口使用process.env.PORT || 8080也正确,平台会自动分配端口。
    • 防火墙规则(Compute Engine):如果用Compute Engine,需在VPC防火墙添加规则,允许目标端口(如8080)的TCP流量,来源设为0.0.0.0/0。
    • App Engine会话亲和性:若使用App Engine灵活环境,需在app.yaml中添加会话亲和性配置,确保WebSocket长连接不被中断:
      runtime: nodejs
      env: flex
      manual_scaling:
        instances: 1
      network:
        session_affinity: true
      
  3. 前端Socket初始化检查
    确认js/index.js中的Socket初始化代码为const socket = io();,因页面由后端提供,相对路径可自动匹配;若配置了错误的绝对URL,会直接导致连接被拒。

  4. 文件存储替代方案
    Google Cloud多数环境(如App Engine)的本地文件系统是临时且可能无写权限,代码中读写count.json可能引发异常,间接影响WebSocket服务。建议替换为Google Cloud Storage或Firestore存储计数数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 22:52:47