为什么 Express 的默认错误处理程序在从可读流发出时捕获错误?
Why does the Express' default error handler catch error when emitting from Readable stream?
我使用命令行 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.okay
为 false
时会引发错误 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
});
});
}
这让我抓狂。错误是如何结束的?为什么事件监听器没有捕捉到它?
1) 当你发出 error
ReadFile returns 什么都没有,以及最近的路由器模块之外的错误陷阱时,然后在调用 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;
}
/**...**/
}
我的想法是 'error' 事件甚至在流对象完成创建之前就已发出。结果节点找不到您附加的 'error' 侦听器,因为它尚未创建并将其作为 Unhandled 'error' event
.
抛出
一种解决方案是使用 setImmediate
延迟事件发出。然后它将创建流对象并在发出错误之前首先绑定错误侦听器:
if (!options.okay) {
setImmediate(function(){
self.emit('error', new Error('Forced crash'));
});
return;
}
我使用命令行 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.okay
为 false
时会引发错误 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
});
});
}
这让我抓狂。错误是如何结束的?为什么事件监听器没有捕捉到它?
1) 当你发出 error
ReadFile returns 什么都没有,以及最近的路由器模块之外的错误陷阱时,然后在调用 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;
}
/**...**/
}
我的想法是 'error' 事件甚至在流对象完成创建之前就已发出。结果节点找不到您附加的 'error' 侦听器,因为它尚未创建并将其作为 Unhandled 'error' event
.
一种解决方案是使用 setImmediate
延迟事件发出。然后它将创建流对象并在发出错误之前首先绑定错误侦听器:
if (!options.okay) {
setImmediate(function(){
self.emit('error', new Error('Forced crash'));
});
return;
}