Node.js并发请求下API响应混乱问题排查求助
兄弟,碰到并发请求下响应串了的问题真的闹心,我帮你捋捋代码里的问题和排查方向哈:
连接释放逻辑重复且错误:你在try块里先调用了
connection.release(),又在finally里调用connection.close()。对于从Oracle连接池获取的连接,正确操作是用release()把连接放回池里循环利用,close()则是直接销毁连接。重复执行这两个操作会导致连接状态异常,后续请求拿到的连接可能不是“干净”的,进而导致不同用户的查询和响应串在一起。建议删掉try块里的connection.release(),只在finally里保留connection.release()来归还连接。请求头获取可能写错了:代码里写的是
req.header.USERNAME,但在Express框架里,获取请求头应该用req.headers.USERNAME(注意是复数的headers)。如果这里写错了,req.header会是undefined,bind数组的第一个参数就会变成undefined,可能导致SQL查询返回错误的数据,看起来像是响应串了。排查全局共享变量:你提到怀疑是全局变量导致的问题,虽然当前给出的代码里没有全局变量,但可以检查下代码外的部分:比如是不是用了全局的单例连接(而不是连接池)?有没有其他全局存储请求上下文的变量(比如全局的bind数组、全局的response对象)?这些全局变量在并发请求下会被不同请求覆盖,直接导致响应串用。
加个请求ID方便排查:可以在每个请求进来时生成一个唯一的request ID,把它和请求参数、查询结果一起打到日志里。这样就能清晰看到每个请求的参数和返回是否对应,定位到底是参数被覆盖了,还是响应发错了对象。
给你改了下代码,你可以参考:
const codeModel = async (req, res) => { let connection; // 生成唯一请求ID,方便排查问题 const reqId = `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; try { connection = await oracledb.getConnection("MS"); // 修正请求头的拼写 const username = req.headers.USERNAME; let lastCodeSQL = `你的正确SQL查询语句`; // 替换成你原来的SQL let bind = [ username, req.body.C_ID, req.body.S_ID, req.body.Q_ID, ]; // 打印日志关联请求ID logger.info(`[${reqId}] 执行查询,参数:`, bind); const lastCodeSQLres = await connection.execute(lastCodeSQL, bind); logger.info(`[${reqId}] 查询结果:`, lastCodeSQLres); res.json(lastCodeSQLres); } catch (err) { logger.error(`[${reqId}] 请求出错:`, err); // 记得给错误请求返回响应,别让客户端一直等 res.status(500).json({ error: err.message }); } finally { try { if (connection) { // 把连接放回池里,而不是销毁 await connection.release(); logger.info(`[${reqId}] 连接已归还到池`); } } catch (err) { logger.error(`[${reqId}] 归还连接出错:`, err); } } };
备注:内容来源于stack exchange,提问作者Vinayak

