【问题标题】:Event emitter doesn't work properly after first request第一次请求后事件发射器无法正常工作
【发布时间】:2019-01-27 21:06:14
【问题描述】:

我的 express.js 应用程序中有一个基本控制器。我尝试执行某个服务,该服务会在稍有延迟后获取模拟数据。该服务继承自EventEmitter,接收到数据后发出SUCCESS事件。

这是我的控制器:

const express = require('express');
const router = express.Router();
const GetAllUsers = require('../GetAllUsers');
const getAllUsers = new GetAllUsers();

router.get('/', function(req, res, next) {
  getAllUsers
    .on('SUCCESS', (users) => {
      res
        .status(200)
        .json({ users });
    })
    .on('ERROR', next);

  getAllUsers.execute();
});

module.exports = router;

和服务:

const EventEmitter = require('events');

class GetAllUsers extends EventEmitter {
  async execute() {
    const data = [{ id: 1, name: 'user 1' }, { id: 2, name: 'user 2' }];

    try {
      const users = await new Promise(resolve => {
        setTimeout(() => {
          resolve(data);
        }, 1000);
      })

      this.emit('SUCCESS', users);
    } catch (error) {
      this.emit('ERROR', error);
    }
  }
}

module.exports = GetAllUsers;

问题是当我第一次进入/users 路径时,我实际上得到了一个用户列表。但是当我第二次及以后尝试时,我收到以下错误:

Cannot set headers after they are sent to the client
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:471:11)
    at ServerResponse.header (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/home/debian/dev/sandbox/emitterTest/node_modules/express/lib/response.js:267:15)
    at GetAllUsers.getAllUsers.on (/home/debian/dev/sandbox/emitterTest/routes/users.js:12:10)
    at GetAllUsers.emit (events.js:187:15)
    at GetAllUsers.execute (/home/debian/dev/sandbox/emitterTest/GetAllUsers.js:14:12)

据我了解,在我发送回复之前,标头已设置在某处。

当我尝试在没有发射器的情况下实现我的控制器时,一切正常:

router.get('/', async function(req, res, next) {
  const data = [{ id: 1, name: 'user 1' }, { id: 2, name: 'user 2' }];

  const users = await new Promise(resolve => {
    setTimeout(() => {
      resolve(data);
    }, 1000);
  })

  res
    .status(200)
    .json({ users });
});

如何解决这个问题?

【问题讨论】:

    标签: node.js express events event-handling eventemitter


    【解决方案1】:

    这是因为每次发出请求时,都会运行路由器功能:

    function(req, res, next) {
      getAllUsers 
        .on('SUCCESS', (users) => { //subscribe to event every time
          res
            .status(200)
            .json({ users });
        })
        .on('ERROR', next);
    
      getAllUsers.execute();
    }
    

    您已订阅这些事件并运行一次。当时,您提出了第二个请求,您有 2 个订阅者:来自上一个请求,以及来自当前。然后,execute() 函数触发事件。所以一次执行了 2 个函数,其中一个,尝试再次发送响应,但这是不可能的,因此会导致错误。

    如果确实需要这些事件发射器,您可以使用getAllUsers.once 函数仅订阅一次触发事件。

    【讨论】:

    • 谢谢!这是一个有用的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    • 2019-12-03
    • 2015-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多