admin管理员组

文章数量:1292704

In Node.js, say that I want to read a file from somewhere and stream the response (e.g., from the filesystem using 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);
});

However, I want to detect if there is an error with the stream before sending my response headers. How do I do that?

Pseudocode:

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();
    });
});

In Node.js, say that I want to read a file from somewhere and stream the response (e.g., from the filesystem using 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);
});

However, I want to detect if there is an error with the stream before sending my response headers. How do I do that?

Pseudocode:

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();
    });
});
Share Improve this question edited Aug 8, 2015 at 17:00 Jackson Ray Hamilton asked Aug 5, 2015 at 23:13 Jackson Ray HamiltonJackson Ray Hamilton 9,4766 gold badges53 silver badges79 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

Write stream is ended when readStream ends or has an error. You can prevent this default behaviour by passing end:false during pipe and end the write stream manually.

So even if the error occurs, your write stream is still open and you can do other stuff(e.g. sending 404 status) with writestream in the error callback.

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

Update 1: For file streams, you can listen for open event to check if the file is ready to read:

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

Update 2: As OP mentioned there may be no open event for other streams, we may use the following if the stream is inherited from node's stream module. The trick is we write the data manually instead of pipe() method. That way we can do some 'initialization' on writable before starting to write first byte.

So we bind once('data') first and then bind on('data'). First one will be called before actual writing is happened.

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

本文标签: javascriptNodejsCheck if stream has error before piping responseStack Overflow