Node.js+Express环境下createReadStream抛出错误无法被catch处理
问题排查与解决方案
核心问题原因
- Promise 仅能捕获构造函数执行过程中同步抛出的错误,你在
entry事件的回调函数里抛出的错误属于异步回调中的异常,不属于Promise构造函数的同步执行上下文,所以不会被Promise的catch捕获,会直接抛出到全局导致进程终止。 - Stream的事件回调里抛出的错误,不会自动触发Stream本身的
error事件,也不会向上传递到你之前监听的ReadStream的error事件,所以你之前写的error监听也捕获不到这里的异常。
修复方案
修复逻辑:给每一段Stream都添加error监听,所有异步回调内的业务逻辑包try/catch,捕获到异常后主动调用Promise的reject方法传递错误,不要直接throw。
修改后的functions.js代码参考:
const fs = require('fs') const unzip = require('unzip') // 补充缺失的依赖引入 module.exports = { test: function (request, response, fichier){ return new Promise((resolve, reject) => { let readStream try { readStream = fs.createReadStream(fichier) .on('error', function(err){ console.log("read stream error") reject(err) }) .on('close', function(){ console.log("read stream end") resolve("ok") }) .pipe(unzip.Parse()) .on('error', function(err) { // 捕获unzip流的所有错误 console.log("unzip stream error") // 销毁上游读流避免内存泄漏 readStream.destroy() reject(err) }) .on('entry', function (entry) { try { // 业务逻辑写在try块内 // throw("uh") 你的测试错误 entry.autodrain() // 必须处理entry,否则流会卡住无法触发结束事件 } catch (e) { // 主动捕获业务异常并传递给Promise console.log("entry handle error") readStream.destroy() reject(e) } }); } catch (e) { // 捕获创建流过程中同步抛出的错误 reject(e) } console.log("end end") }) } }
额外注意事项
- 所有流式操作的每一段链路都必须单独添加
error监听,任何一段流报错没有监听都会直接抛到全局终止进程。 - 处理
unzip的entry事件时,每个entry都必须做消费、丢弃等处理,否则流会暂停卡住,永远不会触发close事件。
内容的提问来源于stack exchange,提问作者infrahinium
相关产品推荐
相关产品推荐

