Jason M
Jason M

Reputation: 1053

In Express js, how do you properly end a stream response that throws an error

badStream.pipe(res)

When badStream throws an error, the response is not terminating and the request in the browser is stuck in a pending state.

badStream.on(error, function() {this.end()}).pipe(res)

I've tried the above to no avail. What's the proper way to handle the error in this case? Thanks for any help.

Upvotes: 3

Views: 5149

Answers (2)

Konstantin Nikolskii
Konstantin Nikolskii

Reputation: 1265

For me add sourceStream.on('error', (e) => { /* your handle logic here */ }) helped to solve similar issue. But it's very important to add it to the SOURCE of the error in other case nodejs, will make your program crash because of uncaughtException is emitted In my case I put the handler to pipe and writableStream, but not sourceStream

Upvotes: 0

jfriend00
jfriend00

Reputation: 707308

In nodejs, an error on the readstream that is piped to the http response stream just unpipes it from the response stream, but does not otherwise do anything to the response stream it was piped to. That leaves it hanging as an open socket with the browser still waiting for it to finish (as you observed). As such, you have to manually handle the error and do something to the target stream.

badStream.pipe(res);
badStream.on('error', err => {
  // log the error and prematurely end the response stream
  console.log(err);
  res.end();
});

Because this is an http response and you are already in the middle of sending the http response body and thus the http status and headers have already been sent, there aren't a lot of things you can do in the middle of sending the response body.

Ultimately, you're going to have to call res.end() to terminate the response so the browser knows the request is done. If there's a content-length header on this response (the length was known ahead of time), then just terminating the response stream before it's done will cause the browser to see that it didn't get the whole response and thus know that something went wrong.

If there's no content-length on the response, then it really depends upon what type of data you're sending. If you're just sending text, then the browser probably won't know there's an error because the text response will just end. If it's human readable text, you could send "ERROR, ERROR, ERROR - response ended prematurely" or some visible text marker so perhaps a human might recognize that the response is incomplete.

If it's some particular format data such as JSON or XML or any multi-part response, then hanging up the socket prematurely will probably lead to a parsing error that the client will notice. Unfortunately, http just doesn't really make provisions for mid-response errors so it's left to the individual applications to detect and handle.

FYI, here's a pretty interesting article that covers a lot about error handling with streams. And, note that using stream.pipeline() instead of .pipe() also does a lot more complete error handling, including giving you one single callback that will get called for an error in either stream and it will automatically call .destroy() on all streams. In many ways, stream.pipeline(src, dest) is meant to replace src.pipe(dest).

Upvotes: 5

Related Questions