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



我使用命令行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);
  });
}

options.okayfalse时抛出错误Forced crash.。我希望在收听error时捕获index.js路由中的错误。但是处理程序永远不会执行。令我非常惊讶的是,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
    });
  });
}

这快把我逼疯了。错误是如何在这里结束的?为什么事件侦听器没有捕捉到它?

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

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

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

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;
  }
  /**...**/ 
}

相关内容

  • 没有找到相关文章

最新更新