Node.js中如何阻止服务器刷新事件重复记录日志?
解决Node.js事件与服务器结合时重复记录日志的问题
问题原因
每次HTTP请求到达服务器时,你都会在请求回调内调用eventemitter.on('log', ...)给log事件新增一个监听器。随着请求次数增加,监听器会不断累积,每次触发emit('log')时,所有已绑定的监听器都会执行,导致同一时间点的日志被重复记录。
解决方案
方案1:将事件监听器移到服务器逻辑外(推荐)
把监听器绑定代码放在http.createServer()外面,只执行一次绑定,这样无论多少请求,监听器始终只有一个,emit只会触发一次回调。
修改后的完整代码:
const {v4:uuid} = require('uuid'); const {format} = require('date-fns'); const EventEmitter = require('events'); const os = require('os'); const path = require('path'); const fs = require('fs'); const http = require('http'); const user = os.userInfo().username; const eventemitter = new EventEmitter(); // 仅绑定一次log事件监听器 eventemitter.on('log', (date_time, res) => { const req_string = `Log event: '${uuid()}' emitted by ${user} at time: ${date_time} hrs.\n`; // 用同步创建文件夹,避免异步创建时还未完成就写入日志 if(!fs.existsSync(path.join(__dirname, 'server_folder'))){ fs.mkdirSync(path.join(__dirname, 'server_folder')); } fs.appendFileSync(path.join(__dirname, 'server_folder', 'server_log.txt'), req_string, 'utf-8'); res.write(req_string); res.end(); }); const server = http.createServer((req, res) => { const date_time = `${format(new Date, 'dd.MM.yyyy HH:mm:ss')}`; // 触发事件时传递需要的参数 eventemitter.emit('log', date_time, res); }); server.listen(5000);
方案2:使用once替代on绑定监听器
如果必须在请求回调内绑定监听器,使用eventemitter.once()代替on(),这样监听器只会被触发一次,触发后会自动从事件中解绑,不会累积。
修改请求回调部分的代码:
const server = http.createServer((req, res)=>{ const date_time = `${format(new Date, 'dd.MM.yyyy HH:mm:ss')}`; // 使用once,监听器触发一次后自动解绑 eventemitter.once('log', ()=>{ const req_string = `Log event: '${uuid()}' emitted by ${user} at time: ${date_time} hrs.\n`; if(!fs.existsSync(path.join(__dirname, 'server_folder'))){ fs.mkdirSync(path.join(__dirname, 'server_folder')); } fs.appendFileSync(path.join(__dirname, 'server_folder', 'server_log.txt'), req_string, 'utf-8'); res.write(req_string); res.end(); }) eventemitter.emit('log'); })
额外优化提示
原代码中fs.mkdir是异步方法,可能出现文件夹还未创建完成就执行appendFileSync的情况,改成同步的fs.mkdirSync可以避免这个潜在问题。
内容的提问来源于stack exchange,提问作者Abhrajit Saha
相关产品推荐
相关产品推荐

