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

NodeJS+Express服务器根路由请求无响应问题排查求助

根路由GET请求无响应的排查与解决

问题描述

使用Node.js + Express搭建服务器并集成Socket.io后,向根路由http://localhost:3000/发送GET请求时无响应,请求一直处于等待状态。相关代码如下:

const express = require("express");
const axios = require("axios");
const cors = require('cors');
const app = express();
const { createClient } = require('redis');
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const db = require('./helper/db')

const io = new Server(server, {
  cors: {
      origin: "*"
  }
});

app.use(express.json());
app.use(cors);
app.use(express.urlencoded({
    extended: true
}))


app.get('/', (req,res) => {
  res.send('Backend NodeJS SO1 Proyecto2');
});

var claves = [];
var total_registros = 0;
var semestre_cursos = [];

async function consultarRedis() {

  const client = await createClient({
    url: 'redis://172.17.0.3:6379'
  })
  .on('error', err => console.log('Redis Client Error', err))
  .connect();

  total_registros = await client.get('total_registros');
  console.log(total_registros)

}

async function consultarRedisSemestre() {
  semestre_cursos = [];
  const client = await createClient({
    url: 'redis://172.17.0.3:6379'
  })
  .on('error', err => console.log('Redis Client Error', err))
  .connect();

  var temp = 0;
  for(var clave of claves){
    try{
      temp = await client.hGet('cursos_semestres', clave)
      semestre_cursos.push(parseInt(temp))
    }catch(error){
      console.error(`Error al consultar Redis para la clave "${clave}":`, error)
    }
  }
}

io.on('connection', (socket) => {
  console.log('Cliente conectado');

  const interval = setInterval(() => {
    consultarRedis();
    socket.emit('total_registros', total_registros);
  }, 1000);

  // Manejar desconexiones de socket.io
  socket.on('disconnect', () => {
    clearInterval(interval);
    console.log('Cliente desconectado');
  });

  socket.on('selectedSemester', (semestreSeleccionado) => {
    claves = [];
    claves.push(`SO1:${semestreSeleccionado}`)
    claves.push(`BD1:${semestreSeleccionado}`)
    claves.push(`LFP:${semestreSeleccionado}`)
    claves.push(`SA:${semestreSeleccionado}`)
    claves.push(`AYD1:${semestreSeleccionado}`)

    const interval = setInterval(async () => {
      temp = await consultarRedisSemestre();
      socket.emit('valores_semestre', semestre_cursos);
    }, 1000);
  
  });

});

server.listen(3000, () => {
  console.log("Server on port 3000");
});

问题排查与解决

1. CORS中间件调用错误

这是导致请求挂起的直接原因:
原代码中app.use(cors);没有调用cors()函数,而是直接将函数本身作为中间件传入。Express中间件需要是一个可执行的处理函数,未调用的cors只是函数引用,会直接阻塞请求处理流程。

修复方式:
将app.use(cors);修改为:

app.use(cors());

2. Redis客户端未关闭连接

每次调用consultarRedis和consultarRedisSemestre都会创建新的Redis客户端,但没有主动关闭连接,长期运行会导致Redis连接池耗尽,阻塞Node.js事件循环,间接影响请求处理效率。

修复方式:
复用Redis客户端,避免重复创建连接:

// 全局复用Redis客户端
let redisClient;

async function initRedisClient() {
  redisClient = createClient({
    url: 'redis://172.17.0.3:6379'
  })
  .on('error', err => console.log('Redis Client Error', err));
  await redisClient.connect();
}

// 初始化客户端
initRedisClient();

async function consultarRedis() {
  if (!redisClient) return;
  try {
    total_registros = await redisClient.get('total_registros');
    console.log(total_registros);
  } catch (err) {
    console.error('Redis查询错误:', err);
  }
}

async function consultarRedisSemestre() {
  semestre_cursos = [];
  if (!redisClient) return;
  for(var clave of claves){
    try{
      const temp = await redisClient.hGet('cursos_semestres', clave);
      semestre_cursos.push(parseInt(temp) || 0); // 处理null返回值
    }catch(error){
      console.error(`Error al consultar Redis para la clave "${clave}":`, error);
    }
  }
}

3. Socket.io定时器内存泄漏

在selectedSemester事件中创建的定时器没有在客户端断开连接时清理,会导致内存泄漏,长期运行会降低服务器稳定性。

修复方式:
将定时器存储在socket对象上,断开连接时统一清理:

socket.on('selectedSemester', (semestreSeleccionado) => {
  claves = [
    `SO1:${semestreSeleccionado}`,
    `BD1:${semestreSeleccionado}`,
    `LFP:${semestreSeleccionado}`,
    `SA:${semestreSeleccionado}`,
    `AYD1:${semestreSeleccionado}`
  ];

  // 清理之前的定时器(如果存在)
  if (socket.semesterInterval) {
    clearInterval(socket.semesterInterval);
  }

  socket.semesterInterval = setInterval(async () => {
    await consultarRedisSemestre();
    socket.emit('valores_semestre', semestre_cursos);
  }, 1000);
});

// 在disconnect事件中清理所有定时器
socket.on('disconnect', () => {
  clearInterval(interval);
  if (socket.semesterInterval) {
    clearInterval(socket.semesterInterval);
  }
  console.log('Cliente desconectado');
});

修改后的完整代码

const express = require("express");
const axios = require("axios");
const cors = require('cors');
const app = express();
const { createClient } = require('redis');
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const db = require('./helper/db')

const io = new Server(server, {
  cors: {
      origin: "*"
  }
});

// 修复CORS中间件调用
app.use(express.json());
app.use(cors());
app.use(express.urlencoded({
    extended: true
}))

app.get('/', (req,res) => {
  res.send('Backend NodeJS SO1 Proyecto2');
});

var claves = [];
var total_registros = 0;
var semestre_cursos = [];

// 全局Redis客户端
let redisClient;

async function initRedisClient() {
  redisClient = createClient({
    url: 'redis://172.17.0.3:6379'
  })
  .on('error', err => console.log('Redis Client Error', err));
  await redisClient.connect();
}

initRedisClient();

async function consultarRedis() {
  if (!redisClient) return;
  try {
    total_registros = await redisClient.get('total_registros');
    console.log(total_registros);
  } catch (err) {
    console.error('Redis查询total_registros错误:', err);
  }
}

async function consultarRedisSemestre() {
  semestre_cursos = [];
  if (!redisClient) return;
  for(var clave of claves){
    try{
      const temp = await redisClient.hGet('cursos_semestres', clave);
      semestre_cursos.push(parseInt(temp) || 0);
    }catch(error){
      console.error(`Error al consultar Redis para la clave "${clave}":`, error);
    }
  }
}

io.on('connection', (socket) => {
  console.log('Cliente conectado');

  const interval = setInterval(() => {
    consultarRedis();
    socket.emit('total_registros', total_registros);
  }, 1000);

  socket.on('disconnect', () => {
    clearInterval(interval);
    // 清理学期定时器
    if (socket.semesterInterval) {
      clearInterval(socket.semesterInterval);
    }
    console.log('Cliente desconectado');
  });

  socket.on('selectedSemester', (semestreSeleccionado) => {
    claves = [
      `SO1:${semestreSeleccionado}`,
      `BD1:${semestreSeleccionado}`,
      `LFP:${semestreSeleccionado}`,
      `SA:${semestreSeleccionado}`,
      `AYD1:${semestreSeleccionado}`
    ];

    // 清理之前的定时器
    if (socket.semesterInterval) {
      clearInterval(socket.semesterInterval);
    }

    socket.semesterInterval = setInterval(async () => {
      await consultarRedisSemestre();
      socket.emit('valores_semestre', semestre_cursos);
    }, 1000);
  });

});

server.listen(3000, () => {
  console.log("Server on port 3000");
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 00:45:57