Handling aborted HTTP requests in NodeJS v17+
I want to know when HTTP requests sent to my Node server are canceled by the user. In the past you could listen to the 'abort' event on a http.ClientRequest
, but that event and it's related fields on the request object have been deprecated since node v16.12. You can still listen to this event. It's continued to work for me, but I don't want to rely on an event that's explicitly deprecated.
TL;DR
Option 1: Listen to 'error' events and check the error code field for 'ECONNRESET'. Optionally check for an err.message
value of 'aborted'.
Option 2: Listen for 'close' events and check the request's readableAborted
property (this field is still considered "experimental" in Node's documentation)
The Details
The deprecated 'abort' event docs say to use the 'close' event as an alternative. Looking at the docs for the 'close' event it doesn't give us any idea how we can distinguish between a forceful connection closing on the client-side and a successful request closing as a result of a completed response.
All resources I found online still suggest using the aborted
property on the http.ClientRequest
object, but again, that's also marked as deprecated.
The request.aborted docs send us to another property request.destroyed. When I tested it, I noticed it behaves similar to the 'close' event in that it is set to true regardless of whether the request was closed forcefully by the client or was closed gracefully by fulfilling the request with a response.
I opened a debugger inside the 'close' event handler to poke around at anything else that was available. I noticed a readableAborted
field that seemed relevant. The http.ClientRequest
extends the stream.Readable
class which provides this field. And to my luck, this field worked as I expected. If the request was aborted by the client, this field was set to true just as the old aborted
field was set. The downside: the documentation labels this field as "experimental". Still better than using a deprecated field, but I'd like to use something that is explicitly "stable".
The only method I've found that isn't caveated by some "experimental" or "deprecated" field/event is listening for generic 'error' events on the http.ClientRequest
object and checking for a code
value of ECONNRESET
. From my testing, these error events also include a message
property that is set to 'aborted'. I'm not entirely sure what other values the message
field could hold for an ECONNRESET error. Checking the error code alone seems to work just fine.
req.on('error', (err) => {
if (err.code === 'ECONNRESET') {
// request aborted by the client
}
})