Node.js – 在pipe道响应之前检查stream是否有错误

在Node.js中,假设我想从某个地方读取一个文件并传输响应(例如,使用fs.createReadStream()从文件系统中)。

 application.get('/files/:id', function (request, response) { var readStream = fs.createReadStream('/saved-files/' + request.params.id); var mimeType = getMimeTypeSomehow(request.params.id); if (mimeType === 'application/pdf') { response.set('Content-Range', ...); response.status(206); } else { response.status(200); } readStream.pipe(response); }); 

但是,我想在发送我的响应头之前检测stream是否有错误。 我怎么做?

伪代码:

 application.get('/files/:id', function (request, response) { var readStream = fs.createReadStream('/saved-files/' + request.params.id); readStream.on('ready', function () { var mimeType = getMimeTypeSomehow(request.params.id); if (mimeType === 'application/pdf') { response.set('Content-Range', ...); response.status(206); } else { response.status(200); } readStream.pipe(response); }); readStream.on('error', function () { response.status(404).end(); }); }); 

当readStream结束或发生错误时,写入stream结束。 您可以通过在pipe道中传递end:false来防止此缺省行为,并手动结束写入stream。

所以,即使发生错误,你的写入stream仍然是打开的,你可以用errorcallback中的writestream做其他的事情(例如发送404状态)。

 var readStream = fs.createReadStream('/saved-files/' + request.params.id); readStream.on('error', function () { res.status(404).end(); }); readStream.on('end', function(){ res.end(); //end write stream manually when readstream ends }) readStream.pipe(res,{end:false}); // prevent default behaviour 

更新1 :对于文件stream,您可以侦听open事件以检查文件是否准备好读取:

 readStream.on('open', function () { // set response headers and status }); 

更新2 :正如OP提到,其他stream可能没有open事件,如果stream是从节点的stream模块inheritance的,我们可以使用以下内容。 诀窍是我们手动写入数据而不是pipe()方法。 这样我们可以在开始写第一个字节之前在可写的地方做一些“初始化”。

所以我们先绑定once('data')然后绑定on('data') 。 第一个将在实际写作发生之前被调用。

 readStream .on('error',function(err) { res.status(404).end(); }) .once('data',function(){ //will be called once and before the on('data') callback //so it's safe to set headers here res.set('Content-Type', 'text/html'); }) .on('data', function(chunk){ //now start writing data res.write(chunk); }) .on('end',res.end.bind(res)); //ending writable when readable ends