ExpressJS与NodeJS接口数组重复,首次请求返回空数组问题
问题分析与解决方案
问题根源
全局数组导致跨请求数据污染
var logtraceArr = [];定义在路由处理函数外部,属于模块级变量。Express的路由模块是单例加载的,所有请求都会共享这个数组。第一次请求时异步操作还没完成就返回空数组,第二次请求时第一次的异步操作已经完成,数组里留存了第一次的数据,同时第二次的异步操作又会往里面追加新内容,导致数据累加。异步流程未正确等待
代码中readFiles、getfileContent里的文件读取、readline事件都是异步操作,但你在调用readFiles后立刻执行res.send(logtraceArr),此时异步操作还未执行完毕,数组自然是空的。
修复后的代码
var express = require("express"); var router = express.Router(); const fs = require("fs").promises; // 使用Promise版fs,简化异步处理 const path = require("path"); const readline = require('readline'); const directoryPath = path.resolve(__dirname, "../logtrace-filestore/edepoze-logs"); router.get("/", async function(req, res, next) { // 每次请求创建全新数组,彻底避免跨请求数据污染 const logtraceArr = []; const fetchFileContentParsed = (fileContentObj) => { const logtraceObj = { Direction: '', FromServer: '', ToServer: '' }; const pipearray = fileContentObj.toString().split("|"); // 移除无意义循环,直接处理目标字段 if (pipearray.length > 5) { const Direction = pipearray[5].split("::"); logtraceObj.Direction = Direction.length === 2 ? Direction[1] : ""; } logtraceArr.push(logtraceObj); }; // 将单个文件的读取解析包装为Promise,确保能被Promise.all等待 const processSingleFile = async (file) => { const filePath = path.join(directoryPath, file); const readStream = fs.createReadStream(filePath); const rl = readline.createInterface({ input: readStream, crlfDelay: Infinity }); return new Promise((resolve) => { rl.on('line', (line) => { const regExp = /\[Event([^]+\])/g; const matchedContent = line.match(regExp); if (matchedContent) { fetchFileContentParsed(matchedContent); } }); rl.on('close', resolve); // 文件读取完成后触发resolve }); }; const getfileContent = async (files) => { // 等待所有文件处理完成 await Promise.all(files.map(file => processSingleFile(file))); }; const readFiles = async (dirname) => { const filenames = await fs.readdir(dirname); // 使用Promise版readdir替代回调 await getfileContent(filenames); }; try { res.header("Access-Control-Allow-Origin", "*"); res.contentType('application/json'); // 等待所有异步操作完成后再返回响应 await readFiles(directoryPath); res.send(logtraceArr); } catch (err) { next(err); // 将错误交给Express错误处理中间件处理 } }); module.exports = router;
关键修改说明
- 数组本地化:把
logtraceArr移到路由处理函数内部,每次请求都生成新数组,彻底解决跨请求数据累加问题。 - 异步流程规范化:
- 改用
fs.promises的API,配合async/await简化异步代码的可读性和流程控制。 - 将
readline的文件读取逻辑包装为Promise,确保Promise.all能正确等待所有文件处理完成。
- 改用
- 等待异步完成再响应:通过
await readFiles(directoryPath)确保所有文件读取、解析完成后再发送响应,保证首次请求就能返回正确数据。 - 冗余代码清理:移除原代码中无意义的
for循环,直接处理目标字段,提升代码效率。 - 错误处理完善:用
try/catch包裹异步操作,将错误传递给Express内置的错误处理中间件,避免请求异常挂起。
内容的提问来源于stack exchange,提问作者SaiPrasad_SP
相关产品推荐
相关产品推荐

