为什么Express'从可读流发出时,默认错误处理程序捕获错误?

时间:2015-08-01 14:05:48

标签: node.js express stream streaming

我使用命令行express stream_test安装了样板Express应用程序。我将默认/routes/index.js替换为:

var express = require('express');
var router = express.Router();
var ReadFile = require('./readFile.js');

/* GET home page. */
router.get('/', function(req, res, next) {
  var readFile = ReadFile();
  readFile
  .on('data', function(data) {
    res.write(data);
  })
  .on('end', function() {
    res.end();
  })
  .on('error', function(err) {
    console.log(err);
  });
});

module.exports = router;

readFile.js只是fs.createReadStream的简单包装器:

var Readable = require('stream').Readable;
var util = require('util');
var fs = require('fs');

function ReadFile(options) {
  if (!(this instanceof ReadFile)) {
    return new ReadFile(options);
  }
  Readable.call(this);

  options = options || {};

  var self = this;

  fs.createReadStream('pride_and_prejudice.txt')
  .on('data', function(data) {
    self.push(data);
  })
  .on('end', function(end) {
    self.push(null);
  });

}

util.inherits(ReadFile, Readable);
ReadFile.prototype._read = function _readGetDeals() {};

module.exports = ReadFile;

这完全没问题。调用路径时,它会将pride_and_prejudice.txt的内容输出到屏幕。

但是,让我们说一些要求没有达到,我想在流式传输数据之前抛出错误:

var Readable = require('stream').Readable;
var util = require('util');
var fs = require('fs');

function ReadFile(options) {
  if (!(this instanceof ReadFile)) {
    return new ReadFile(options);
  }
  Readable.call(this);

  options = options || {};

  var self = this;

  if (!options.okay) {
    return self.emit('error', new Error('Forced crash'));
  }

  fs.createReadStream('pride_and_prejudice.txt')
  .on('data', function(data) {
    self.push(data);
  })
  .on('end', function(end) {
    self.push(null);
  });

}

Forced crash.options.okay时,会引发错误false。我希望在收听index.js时听到error路线中的错误。但处理程序永远不会执行。令我惊讶的是app.js中的默认错误处理程序正在捕获错误:

if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

这让我疯了。错误是如何结束的?为什么事件监听者没有抓住它?

2 个答案:

答案 0 :(得分:1)

1)当您发出error时,ReadFile不返回任何内容,以及最近的路由器模块外部错误的陷阱,然后在调用后调用ReadFile。

2)您可以使用try-catch

try {
  var readFile = ReadFile();
} catch(e) {
  console.log(e);
}

3)或使用回调进行错误:

function ReadFile(options, errorCallback) {
  /**...**/
  if (!options.okay) {
    errorCallback( new Error('Forced crash') );
    return;
  }
  /**...**/ 
}

答案 1 :(得分:1)

我的想法是'错误'甚至在流对象完成创建之前就会发出事件。结果节点没有找到错误'您附加的侦听器,因为它尚未创建并将其作为Unhandled 'error' event抛出。

一种解决方案是使用setImmediate延迟事件发出。然后,它会在发出错误之前先创建流对象并绑定错误侦听器:

 if (!options.okay) {
    setImmediate(function(){ 
      self.emit('error', new Error('Forced crash')); 
    });
    return;
  }