The https library in Nodejs enables us to make https calls to APIs under SSL/TLS protocols (encrypted channels). When there is a communication problem in the channel, the channel is dropped from the server and the ECONNRESET error is raised on the client-side.
In Nodejs, this exception usually has the following exception detail with code source (this changes with new versions).
{ Error: read ECONNRESET
at TLSWrap.onStreamRead (internal/stream_base_commons.js:111:27)
errno: 'ECONNRESET',
code: 'ECONNRESET', syscall: 'read' }
|
This error is confusing because it is created by the TLSWrap.onStreamRead which may lead us to think that there is a TLS problem in communication. This is often a case when the client support version TLS 1.1 and the server only has a more recent version like TLS 1.3.
Before we start making all kinds of changes, we need to make sure that when we make a request, we do not leave the request open. When a request is made, we must always call the end() method of the ClientRequest object. This method is inherited (extended in TypeScript) from the WritableStream class.
When we make a request and do not call the end method, a socket connection is left open (internal implementation of HTTPS with TLS writable stream). Since there is not an explicit socket connection sending data to the server, the request will just hang, and the server will eventually just reset the connection thus the ECONNRESET exception on the client.
Take a look at this code snippet with the corresponding operations to terminate the request and handle other possible communication errors with the server. Take notice of the timeout and end operations.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ClientRequest} from "http"; | |
import http = require("https"); | |
/** | |
* https request class in typesript to show how to manage errors and events | |
* to help prevent ECONNRESET errors | |
*/ | |
export class HttpRequest { | |
public async send(options: http.RequestOptions, data?: any): Promise<any> { | |
let result:string = ""; | |
const promise = new Promise( (resolve, reject) => { | |
const req:ClientRequest = http.request(options, (res) => { | |
console.log('statusCode:', res.statusCode); | |
console.log('headers:', res.headers); | |
res.on("data", chunk => { | |
result += chunk; | |
}); | |
res.on("error", err => { | |
console.log(err); | |
reject(err); | |
}); | |
res.on("end", () => { | |
try { | |
let body = result; | |
//there are empty responses | |
if (res.statusCode === 200) { | |
body = JSON.parse(result); | |
} | |
console.log(res.statusCode, result); | |
resolve(body); | |
} catch (err) { | |
console.log(err); | |
reject(err); | |
} | |
}); | |
}); | |
/*** | |
* handles the errors on the request | |
*/ | |
req.on("error", (err) => { | |
console.log(err); | |
reject(err); | |
}); | |
/*** | |
* handles the timeout error | |
*/ | |
req.on('timeout', (err) => { | |
console.log(err); | |
req.abort(); | |
}); | |
/*** | |
* unhandle errors on the request | |
*/ | |
req.on('uncaughtException', (err) => { | |
console.log(err); | |
req.abort(); | |
}); | |
/** | |
* adds the payload/body | |
*/ | |
if (data) { | |
const body = JSON.stringify(data); | |
req.write(body); | |
} | |
/** | |
* end the request to prevent ECONNRESETand socket hung errors | |
*/ | |
req.end(() => { | |
console.log('request ends'); | |
}); | |
}); | |
return promise; | |
} | |
} | |
/** | |
* entry point function to make a http request | |
*/ | |
const main = async () =>{ | |
/** | |
* define the http request options | |
*/ | |
const requestOptions:http.RequestOptions = { | |
hostname: "hostname.com", | |
method: "GET", | |
path: "/api/data", | |
port: 443, | |
headers: { | |
Accept: "application/json;odata=verbose", | |
Authorization: "auth-token", | |
"Content-Type": "application/json;odata=verbose", | |
}, | |
timeout: 5 * (1000) //n seconds | |
//TLS options below | |
//secureProtocol: 'TLSv1_method', | |
}; | |
const request = new HttpRequest(); | |
const resp = await request.send(requestOptions); | |
console.log(resp); | |
} | |
//run the main function | |
main(); |
Thanks for reading.
0 comments :
Post a Comment
What do you think?