Express调用Node脚本demo.js时无法创建result.json文件的问题
问题分析与解决
问题场景
我搭建了一个Express服务器,流程如下:
- 接收POST请求的JSON数据,写入
./solver/src/test.json文件 - 通过
childProcess.fork调用demo.js脚本 demo.js读取test.json完成计算后,写入result.json- 服务器读取
result.json并返回给客户端
遇到的问题:直接在终端执行node demo.js时,能正常生成result.json;但通过Express服务器调用脚本时,脚本能正常执行(可打印计算结果),却无法生成result.json,导致服务器因找不到文件抛出异常。
相关代码
Express服务器代码
// Function that runs the demo.js script function runScript(scriptPath, callback) { // keeps track of whether callback has been invoked to prevent multiple invocations var invoked = false; var process = childProcess.fork(scriptPath); // listen for errors as they may prevent the exit event from firing process.on('error', function (err) { if (invoked) return; invoked = true; callback(err); }); // execute the callback once the process has finished running process.on('exit', function (code) { if (invoked) return; invoked = true; var err = code === 0 ? null : new Error('exit code ' + code); callback(err); }); } app.post('/', (req, res) => { console.log("Received"); fs.writeFile('./solver/src/test.json', JSON.stringify(req.body) , err => { if(err){ console.error(err); } }); runScript('./solver/src/demo.js', function (err) { if (!err){ fs.readFile('./solver/src/result.json', (err, data) => { if(err) throw err; const jsonResp = JSON.stringify(data); res.send(data); console.log('finished running some-script.js'); }); } else { console.error(err); } }); });
demo.js代码
// result is a string generated by previous instructions // contained in the demo.js file, it gets correctly // printed by the console.log at the end of the script fs.writeFile('./result.json', JSON.stringify(result) , (err) => { if(err){ console.error(err); } else{ console.log("File created succesfully"); } }); console.log(JSON.stringify(result, null, 1));
问题原因
- 工作目录不一致:终端直接运行
demo.js时,工作目录是脚本所在的./solver/src/;但Express调用childProcess.fork时,子进程的工作目录是服务器的启动目录,而非demo.js所在目录。因此./result.json会被写入服务器启动目录,而非预期的./solver/src/,导致服务器找不到文件。 - 异步操作未等待:
fs.writeFile是异步操作,可能在test.json未完全写入时就启动了demo.js,不过从现象看,这不是主要问题,但会引发潜在的读取异常。
修复方案
方案1:指定子进程工作目录
修改runScript函数中的fork调用,添加cwd参数,将子进程工作目录设置为demo.js所在目录:
// 先引入path模块 const path = require('path'); function runScript(scriptPath, callback) { var invoked = false; // 设置子进程工作目录为脚本所在路径 var process = childProcess.fork(scriptPath, { cwd: path.dirname(scriptPath) }); // 后续监听逻辑不变... }
方案2:等待文件写入完成后再启动脚本
修改POST路由,确保test.json写入完成后再调用demo.js,避免读取未完成的文件:
app.post('/', (req, res) => { console.log("Received"); fs.writeFile('./solver/src/test.json', JSON.stringify(req.body) , err => { if(err){ console.error(err); return res.status(500).send('写入test.json失败'); } // 等待文件写入完成后再启动脚本 runScript('./solver/src/demo.js', function (err) { if (!err){ fs.readFile('./solver/src/result.json', (err, data) => { if(err) { console.error(err); return res.status(500).send('读取result.json失败'); } res.send(data); console.log('finished running demo.js'); }); } else { console.error(err); res.status(500).send('执行demo.js失败'); } }); }); });
方案3:在demo.js中使用绝对路径
修改demo.js,用__dirname拼接文件路径,确保写入到脚本所在目录:
const path = require('path'); // ... 其他计算逻辑 fs.writeFile(path.join(__dirname, 'result.json'), JSON.stringify(result) , (err) => { if(err){ console.error(err); } else{ console.log("File created succesfully"); } }); console.log(JSON.stringify(result, null, 1));
注意事项
- 优先使用方案1+方案2,既保证工作目录正确,又避免异步操作的时序问题。
- 处理文件读写错误时,不要直接抛出异常,应返回客户端对应的错误响应,避免服务器崩溃。
内容的提问来源于stack exchange,提问作者grizzo
相关产品推荐
相关产品推荐

