You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

NodeJS+Express服务器路由挂起问题求助(Passport认证、Nginx代理环境)

我之前维护Express+Passport服务的时候也碰到过一模一样的问题——运行一段时间后所有请求都卡着不动,重启就好。结合自己踩的坑和社区里的讨论,整理了几个最常见的原因和对应的解决思路:

常见原因及解决办法

1. Passport会话内存堆积

默认情况下,Passport依赖的express-session是把会话存在内存里的。如果用户量上去、会话过期时间设得太长,或者序列化/反序列化逻辑有问题,内存会越积越多,最终把Node的事件循环堵死,请求就处理不了了。

解决思路:

  • 把会话存到外部存储,比如用connect-redis或者connect-mongo配合express-session,把会话数据放到Redis或者MongoDB里,别占Node的内存。
  • 给会话设合理的过期时间,比如:
    app.use(session({
      secret: 'your-secret-key',
      resave: false,
      saveUninitialized: false,
      cookie: { maxAge: 24 * 60 * 60 * 1000 } // 24小时过期
    }));
    
  • 检查你的passport.serializeUserpassport.deserializeUser函数,别在里面引用大对象或者做不必要的操作,避免内存泄漏。

2. Nginx反向代理的连接配置问题

Nginx和Node之间的连接如果没配置好,也会导致请求卡壳。比如连接超时设置太长,或者长连接没启用,导致连接池耗尽。

解决思路:

  • 在Nginx的location配置里加上这些参数:
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    
    启用HTTP/1.1长连接,同时设置合理的超时时间,避免Nginx一直等无响应的请求。
  • 检查Nginx的worker_connections参数,确保它能处理足够的并发连接,默认值可能不够用。

3. 事件循环被阻塞

如果你的代码里有同步的耗时操作(比如大文件同步读取、复杂的同步计算),或者有未处理的Promise拒绝、重复绑定的事件监听,都会把Node的事件循环卡住,请求自然就处理不了了。

解决思路:

  • clinic.js工具排查阻塞点,它能帮你找到哪些函数占用了大量CPU时间。或者用node --inspect启动服务,在Chrome DevTools里分析事件循环。
  • 全局监听未处理的错误,避免进程静默挂掉:
    process.on('unhandledRejection', (reason, promise) => {
      console.error('未处理的Promise拒绝:', promise, '原因:', reason);
      // 这里可以记录日志,甚至触发进程重启
    });
    
    process.on('uncaughtException', (err) => {
      console.error('未捕获的异常:', err);
      // 安全重启进程,比如用PM2自动重启
    });
    
  • 检查路由或者中间件里有没有重复绑定事件的情况,比如每次请求都绑定一次'data'事件,这样会导致事件监听越来越多,内存泄漏。

4. 进程管理不到位

如果没用到进程管理器,或者配置不合理,Node进程可能因为内存泄漏或者错误挂掉,但没人帮它重启,导致请求无响应。

解决思路:

  • 用PM2来管理你的Node进程,它能自动重启挂掉的进程,还能设置内存阈值:
    pm2 start app.js --max-memory-restart 500M
    
    意思是当进程内存超过500MB时自动重启,避免内存泄漏拖垮服务。
  • 开启PM2的日志功能,pm2 logs能帮你查看进程重启的原因,方便排查问题。

5. 数据库连接泄漏

如果你的应用用到数据库,比如MongoDB、MySQL,要是没正确管理连接池,每次请求都创建新连接不释放,数据库连接会被耗尽,进而导致Node请求挂起。

解决思路:

  • 用数据库的连接池功能,比如Mongoose默认就有连接池,配置合理的连接数:
    mongoose.connect('mongodb://localhost:27017/your-db', {
      poolSize: 10 // 根据并发量调整
    });
    
  • 别手动创建数据库连接后忘记释放,尽量交给连接池管理。

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

火山引擎 最新活动