NodeJS+Express中fs.writeFileSync并发问题:是否需额外处理?
问题:Node.js/Express文件操作的并发安全性疑问
你当前的代码通过/new/answer端点接收JSON格式的questionId和answer,逻辑是读取answers.json:若对应问题存在则追加答案,不存在则新增问题及答案列表。你认为当两个客户端同时调用该端点时,Node.js会自动处理并发,不会出现文件覆盖,两个请求的结果都会保存,想确认这个观点是否正确,是否需要额外实现并发控制逻辑。
const express = require("express"); const fs = require("fs"); const bodyParser = require("body-parser"); const jsonParser = bodyParser.json(); const hostname = "127.0.0.1"; let port = 3001; const app = express(); app.use(express.static(__dirname + "/answers")); const answersPath = __dirname + "/answers/answers.json"; app.patch("/new/answer", jsonParser, function (req, res) { try { const questionId = req.body.questionId; const answer = req.body.answer; const answersJson = JSON.parse(fs.readFileSync(`${answersPath}`, "utf8")); if (answersJson[questionId]) { answersJson[questionId] = [...answersJson[questionId], answer]; } else { answersJson[questionId] = [answer]; } fs.writeFileSync(`${answersPath}`, JSON.stringify(answersJson)); res.sendStatus(200); } catch (e) { console.error(e); res.sendStatus(500); } }); app.listen(port); console.log(`Server running at http://${hostname}:${port}/`);
回答
你的观点在当前代码的前提下部分正确,但需要结合具体场景分析:
当前代码不会出现文件覆盖的原因
你使用的是fs.readFileSync和fs.writeFileSync这类同步阻塞的文件操作API。Node.js基于单线程事件循环模型,当第一个请求进入处理函数后,所有同步代码会连续执行:从读取文件、修改数据到写入文件,整个过程会阻塞事件循环,第二个请求的处理逻辑必须等第一个请求的所有同步操作完成后才会开始执行。这种情况下,两个请求的文件操作是串行的,自然不会出现文件覆盖的问题。
仍需重视并发控制的原因
- 性能瓶颈:同步阻塞的文件操作会拖慢服务整体响应速度,一旦有大量请求同时进入,会导致请求排队等待,服务吞吐量急剧下降。
- 代码迭代风险:如果后续为了优化性能,将同步API替换为异步的
fs.readFile/fs.writeFile或者fs.promises下的异步方法,此时就会出现典型的竞态条件:两个请求同时读取文件,各自修改后先后写入,后写入的内容会覆盖先写入的修改,直接导致数据丢失。
优化建议
如果要兼顾性能和并发安全,推荐以下两种方案:
- 使用文件锁:借助文件锁类库,在读写文件前获取锁,确保同一时间只有一个请求能操作目标文件。
- 改用数据库存储:用轻量型数据库(如SQLite、LevelDB)替代JSON文件,数据库本身已实现完善的并发控制机制,既能避免此类问题,又能提升性能和扩展性。
内容的提问来源于stack exchange,提问作者einazare
相关产品推荐
相关产品推荐

