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

如何让部署在cPanel上的Node.js服务器保持长连接?

Node.js长连接在Namecheap cPanel上5分钟断开,无法维持12小时以上

我在Namecheap的cPanel上部署了Node.js服务器,功能是监听HTTP请求,建立连接后向客户端推送当前连接数和时间信息,同时每秒向Firebase发送时间戳。但现在连接总会在5分钟左右断开,达不到维持12小时以上的需求。

我已经试过这些方法,但都没用:

  • 调整server.keepAliveTimeout、server.headersTimeout、server.setTimeout为超大值或0
  • 在连接实例(sokk)上设置相同的超时参数
  • 配置Cron Jobs定期发起请求
  • 升级到商务主机

我的定时任务只有在连接存续期间才会运行,所以必须解决长连接维持的问题。

附服务器代码:

const https = require('https');
const http = require('http');
http.globalAgent.keepAlive = true; //for persistant connections (last long connections)
const express = require("express");
const app = express();

const server = http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/plain'
    });
    
    setInterval(() => {
        
        server.getConnections(function(error, count) {
            res.write(count + '   ' + new Date() + "\n");
        });
        
    }, 60000);
        
}, app).listen();

server.on("connection", function(sokk) {
    
    sokk.keepAliveTimeout = 86400000 + 1000;
    sokk.headersTimeout = 86400000 + 2000;
    
    setInterval(() => {
        rootRef.child("Servers/Server").child("conn").set(Date.now());
    }, 1000);
    
    sokk.on("data", data => {
        console.log(data);
    });
    
    console.log("A new connection was made by a client.");
});

// server.setTimeout(86400000); // A value of 0 will disable the timeout behavior on incoming connections: https://nodejs.org/dist/latest-v6.x/docs/api/all.html#http_request_settimeout_timeout_callback

// This is the important stuff
server.keepAliveTimeout = 86400000 + 1000;
server.headersTimeout = 86400000 + 2000;

解决方案

1. 调整cPanel/Apache反向代理超时

Namecheap的cPanel主机默认通过Apache做反向代理转发Node.js请求,Apache默认Timeout和ProxyTimeout是300秒(5分钟),这大概率是连接断开的核心原因:

  • 联系Namecheap客服,要求将这两个参数调整为43200秒(12小时)
  • 若主机允许自定义.htaccess,添加以下配置:
    Timeout 43200
    ProxyTimeout 43200
    

2. 修复Node.js代码的问题

你的代码存在内存泄漏、未处理连接关闭等隐患,修改后示例:

const http = require('http');
const express = require("express");
const app = express();

// 全局Agent配置
http.globalAgent.keepAlive = true;
http.globalAgent.keepAliveMsecs = 43200000;

const server = http.createServer(function(req, res) {
    // 添加keep-alive响应头
    res.writeHead(200, {
        'Content-Type': 'text/plain',
        'Connection': 'keep-alive',
        'Keep-Alive': 'timeout=43200, max=1000'
    });

    // 定时推送数据的定时器
    const pushInterval = setInterval(() => {
        server.getConnections(function(error, count) {
            if (error) {
                console.error('获取连接数失败:', error);
                clearInterval(pushInterval);
                res.end();
                return;
            }
            // 确保连接未断开再写入
            if (!res.writableEnded) {
                res.write(`${count}   ${new Date()}\n`);
                res.flushHeaders(); // 强制刷新缓冲区,避免数据积压
            } else {
                clearInterval(pushInterval);
            }
        });
    }, 60000);

    // 监听连接关闭,清理定时器
    res.on('close', () => {
        clearInterval(pushInterval);
        console.log('客户端连接关闭,清理推送定时器');
    });

    // 处理响应错误
    res.on('error', (err) => {
        console.error('响应出错:', err);
        clearInterval(pushInterval);
    });
}, app).listen();

// 服务器级别超时配置
server.keepAliveTimeout = 43200000 + 1000;
server.headersTimeout = 43200000 + 2000;
server.setTimeout(43200000);

server.on("connection", function(socket) {
    // 设置socket超时
    socket.setTimeout(43200000);
    socket.keepAliveTimeout = 43200000 + 1000;
    socket.headersTimeout = 43200000 + 2000;

    // 每个连接对应一个Firebase定时器,连接断开时清理
    const firebaseInterval = setInterval(() => {
        if (!socket.destroyed) {
            rootRef.child("Servers/Server").child("conn").set(Date.now());
        } else {
            clearInterval(firebaseInterval);
        }
    }, 1000);

    socket.on("data", data => {
        console.log(data.toString());
    });

    socket.on('close', () => {
        clearInterval(firebaseInterval);
        console.log('客户端连接断开,清理Firebase定时器');
    });

    socket.on('error', (err) => {
        console.error('socket出错:', err);
        clearInterval(firebaseInterval);
    });

    console.log("新客户端连接建立");
});

3. 客户端侧配合

确保客户端请求携带Connection: keep-alive头,不要主动关闭连接。如果是浏览器端,建议用EventSource或WebSocket代替普通HTTP长连接——浏览器对普通HTTP长连接的超时限制更严格。

4. 检查防火墙/CDN限制

如果启用了Cloudflare等CDN或主机内置防火墙,这些服务通常也有默认连接超时(比如Cloudflare默认100秒),需要同步调整对应超时参数。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 15:27:43