I m running an Express 4 application, and I added some logic to router:
router.get('/pars', function(req, res, next) {
fetcher.parseXml(function(err, result){ //download files from ftp server, it can takes from 10 sec to 1 minute
if(err) {
console.log("router " + err);
res.render('index', { title: err });
}else {
console.log(result);
res.render('index', { title: 'Download finish' });
}
});
});
And added coressponding button to start index page, that send ajax to that '/pars' endpoint:
...
<button id="btn">Parse Data</button>
<script>
$( document ).ready(function() {
$('#btn').click(function () {
$.get(
"/pars",
onAjaxSuccess
);
});
function onAjaxSuccess(data) {
alert(data);
};
});
</script>
So all works fine and I sucesfully reloading page and downloading files from ftp using 'jsftp' module, but after some time (it may be 30 sec or 2 minutes ) I got error which crash all my app:
events.js:85
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:746:11)
at TCP.onread (net.js:559:26)
I found similar problem at Node js ECONNRESET
And added this 'catching' code to my app.js:
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
Now app doesnt crashes, but spams that error from time to timeto my log, and all logic works fine.
I think issue can be in ftp.get:
Ftp.get(config.get("ftpDownloader:dir") + '/'+ fileName, __dirname + '/xml/' + fileName, function(hadErr) {
if (hadErr){
log.error('There was an error retrieving the file.' + hadErr);
ftpDonwloadCallback(hadErr);
}else{
log.info("XML WAS DOWNLOADED: " + fileName);
readFile(fileName, ftpDonwloadCallback);
}
});
Maybe somebody can help me how I can fix that problem?
depends on the error info:
events.js:85
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:746:11)
at TCP.onread (net.js:559:26)
it's caused by TCP connection. if the underlying socket receive a 'error' event, but no 'error' event listener, it will propagate and crash you process.
check your http server, add error event listener to it.
for example:
var server = http.createServer(function(request, response){ ... ... });
server.on('error', function(err) { ... ... });
if you want to catch the error from client, you can listener 'clientError' event.
Related
I am trying to create a route so that when someone accesses it, it will download a file and send a response message to the user (should appear in the HTML). I am using the download function from express JS but it failed.
This is my code:
router.get('/api/zip', AuthMiddleware, (req, res) => {
//console.log("hello");
//return res.status(200).download(".\\views\\index.zip"); => download but doesn't send message to the user.
res.download(".\\views\\index.zip", "index.zip", (err) => {
if (err) {
res.status(500).send({
message: "Could not download the file. " + err,
});
} else {
try {
res.status(200).send("Download!");
} catch (error) {
res.status(500).send("Download fail 2");
}
}
});
});
After the user access http://localhost:4000/api/zip, it downloads the file and the server crashes:
[nodemon] starting `node index.js`
Listening on port 4000
_http_outgoing.js:561
throw new ERR_HTTP_HEADERS_SENT('set');
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (internal/errors.js:322:7)
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse.header (D:\MyProject\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (D:\MyProject\node_modules\express\lib\response.js:174:12)
at D:\MyProject\routes\index.js:34:21
at D:\MyProject\node_modules\express\lib\response.js:450:22
at SendStream.onend (D:\MyProject\node_modules\express\lib\response.js:1078:5)
at SendStream.emit (events.js:400:28)
at ReadStream.onend (D:\MyProject\node_modules\send\index.js:813:10)
at ReadStream.emit (events.js:412:35) {
code: 'ERR_HTTP_HEADERS_SENT'
I understand that I can't use download and then send, so how can I download and send message to the user on the HTML page?
You already know that you can't send 2 responses one after the other.
What can be done, is setting a custom header for your response, so something like this:
app.get('/download', (req, res) => {
res.append('message', JSON.stringify({ message : "hello"}) );
res.download("test.txt", "try.txt");
});
And then get the message from that, It feels really "hacky" though...
I'm getting a reoccuring error that crashes my program.
In the program, I'm consistantly making async requests (one by one I should say)
to download specific images off the internet, this is my code for the request:
const urlDownload = (uri, filename, callback) => {
try {
console.log('start url');
console.log(uri);
request.head(uri, function(err, res, body){
if(err) {
console.log('request error!');
console.log(err);
} else {
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
console.log('end url');
}
// console.log('content-type:', res.headers['content-type']);
// console.log('content-length:', res.headers['content-length']);
});
} catch(e) {
console.log('urlDownload issue');
console.log(e);
}
}
Now, sometimes it doesn't crash, but I feel like 50% or more of the times it does with this exact error:
node:events:368
throw er; // Unhandled 'error' event
^
Error: aborted
at connResetException (node:internal/errors:691:14)
at TLSSocket.socketCloseListener (node:_http_client:407:19)
at TLSSocket.emit (node:events:402:35)
at node:net:687:12
at TCP.done (node:_tls_wrap:580:7)
Emitted 'error' event on Request instance at:
at Request.onerror (node:internal/streams/legacy:62:12)
at Request.emit (node:events:390:28)
at IncomingMessage.<anonymous> (/home/mrz/Desktop/DEVELOPMENT/node_modules/request/request.js:1079:12)
at IncomingMessage.emit (node:events:390:28)
at emitErrorNT (node:internal/streams/destroy:157:8)
at emitErrorCloseNT (node:internal/streams/destroy:122:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
code: 'ECONNRESET'
}
I don't know what to do, tried to search about it and found nothing really,
nothing wrong with the URL it tries to download too!
based on the console logs I have made, it seems like it crashes AFTER it ends the request process successfully I think, because I do get the output, and then it crashes, that's just speculations, I have no idea what's going on.
I am using mongooose to connect mongodb but i am getting following error
/Users/uchitkumar/api/node_modules/mongodb/lib/mongo_client.js:804
throw err;
^
AssertionError [ERR_ASSERTION]: handler (func) is required
at new AssertionError (internal/errors.js:315:11)
at _toss (/Users/uchitkumar/api/node_modules/assert-plus/assert.js:22:11)
at Function.out.(anonymous function) [as func] (/Users/uchitkumar/api/node_modules/assert-plus/assert.js:122:17)
at process (/Users/uchitkumar/api/node_modules/restify/lib/server.js:1352:20)
at argumentsToChain (/Users/uchitkumar/api/node_modules/restify/lib/server.js:1361:12)
at Server.serverMethod [as put] (/Users/uchitkumar/api/node_modules/restify/lib/server.js:1475:21)
my code for connection is as follow
server.listen(config.port, function() {
mongoose.connection.on('error', function(err) {
console.log('Mongoose default connection error: ' + err)
process.exit(1)
})
mongoose.connection.on('open', function(err) {
if (err) {
console.log('Mongoose default connection error: ' + err)
process.exit(1)
}
console.log(
'%s v%s ready to accept connections on port %s in %s environment.',
server.name,
config.version,
config.port,
config.env
)
require('./routes')
})
global.db = mongoose.connect(config.db.uri)
})
routes code
server.get('/', function indexHTML(req, res, next) {
fs.readFile(__dirname + '/../index.html', function (err, data) {
if (err) {
next(err);
return;
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(data);
next();
});
});
This was fine ... I changed something and now it stopped working with this error. The error is that it is not able to assert some function... in mongodb client. it needed a function. Is it asking to add some handler function? where to add that
Thank in advance
handler (func) is required is an error that is thrown by restify if one of your routes or middlewares is undefined.
For example:
server.put('/foo/');
This would also trigger it:
var myMidelware = undefined; // todo: define this
app.put('/route', myMiddleware, (req, res) => { /* todo: handle req */ })
That will throw the error handler (func) is required when it tries to validate that myMidelware is a function.
I don't see that in your posted routes code, but I think it's happening somehow. Do you have a PUT method defined somewhere?
(The same error would also happen with server.get(), server.post(), etc, but the [as put] in the stack trace indicates that it's choking on a server.put() call.)
See https://github.com/restify/node-restify/blob/v7.2.1/lib/server.js#L1386
Also, I don't believe the error has anything to do with mongodb; mongo is just in the stack because you run require('./routes') in the mongo connection open handler. The error is coming from your routes file. Annoyingly, mongo's error handling is loosing part of the stack trace. If you moved require('./routes') to outside of the mongo stuff, it would give you the proper stack trace.
I'm trying to catch mongodb disconnection event.
It works fine with the following setup:
simple.js
'use strict';
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/pnsockets', function () {
console.log('mongoose connected');
});
mongoose.connection.on('disconnected', function () {
console.log('mongoose disconnected');
});
If simple.js is running and I stop mongodb (launchctl stop homebrew.mxcl.mongodb), I get mongoose disconnected on the console, and I can handle the issue.
But running extended.js that is usung socket.io-adapter-mongo, when I kill mongodb, I get the following error:
/project/node_modules/mongoose/node_modules/mongodb/lib/utils.js:98
process.nextTick(function() { throw err; });
^
MongoError: server localhost:27017 timed out
at null.<anonymous> (/project/node_modules/mongodb-core/lib/topologies/server.js:436:40)
at emitTwo (events.js:87:13)
at emit (events.js:172:7)
at null.<anonymous> (/project/node_modules/mongodb-core/lib/connection/pool.js:144:10)
at g (events.js:260:16)
at emitTwo (events.js:87:13)
at emit (events.js:172:7)
at Socket.<anonymous> (/project/node_modules/mongodb-core/lib/connection/connection.js:172:12)
at Socket.g (events.js:260:16)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at TCP._onclose (net.js:468:12)
extended.js
'use strict';
var mongoose = require('mongoose');
var socketIO = require('socket.io');
var MongoAdapter = require('socket.io-adapter-mongo');
mongoose.connect('mongodb://localhost:27017/pnsockets', function () {
console.log('mongoose connected');
_setupSocketAdapter();
});
mongoose.connection.on('disconnected', function () {
console.log('mongoose disconnected');
});
var _setupSocketAdapter = function () {
var io = socketIO();
var socket = mongoose.connections[0].db;
socket.connection = mongoose.connections[0]; // mubsub will need this line
var mongoAdapter = MongoAdapter({socket: socket});
io.adapter(mongoAdapter);
};
How can I catch the MongoError: server localhost:27017 timed out error?
The problem is coming from socket.io-adapter-mongo itself.
If you take a look at the source code, they're using mubsub. Mubsub is basically a pub / sub implementation for Node.js and MongoDB.
They're setting up a client and a channel which is mapping one-to-one with a capped collection but there is no event handler attached on these parts.
According to the mubsub documentation, the following event are available on a channel: *, message, document, ready and error. The error event is also available on the client.
For example, simply adding the following code would catch the errors you're having.
channel.on('error', function (err) {
console.error(err.message);
});
client.on('error', function (err) {
console.error(err.message);
});
In case of a disconnection, you'll get the following output instead of the unhandled error.
mongoose connected
server localhost:27017 timed out
mongoose disconnected
Mubsub: broken cursor.
I wrote simple proxy on nodejs and it looks like
var request = require( 'request' );
app.all( '/proxy/*', function( req, res ){
req.pipe( request({
url: config.backendUrl + req.params[0],
qs: req.query,
method: req.method
})).pipe( res );
});
It works fine if remote host is available, but if remote host is unavailable the whole node server crashes with unhandled exception
stream.js:94
throw er; // Unhandled stream error in pipe.
^
Error: connect ECONNREFUSED
at errnoException (net.js:901:11)
at Object.afterConnect [as oncomplete] (net.js:892:19)
How can I handle such errors?
Looking at the docs (https://github.com/mikeal/request) you should be able to do something along the following lines:
You can use the optional callback argument on request, for example:
app.all( '/proxy/*', function( req, res ){
req.pipe( request({
url: config.backendUrl + req.params[0],
qs: req.query,
method: req.method
}, function(error, response, body){
if (error.code === 'ECONNREFUSED'){
console.error('Refused connection');
} else {
throw error;
}
})).pipe( res );
});
Alternatively, you can catch an uncaught exception, with something like the following:
process.on('uncaughtException', function(err){
console.error('uncaughtException: ' + err.message);
console.error(err.stack);
process.exit(1); // exit with error
});
If you catch the uncaught exception for ECONNREFUSED make sure to restart your process. I saw in testing that the socket becomes unstable if you ignore the exception and simply try to re-connect.
Here's a great overview: http://shapeshed.com/uncaught-exceptions-in-node/
I ended up using the "forever" tool to restart my node process, with the following code:
process.on('uncaughtException', function(err){
//Is this our connection refused exception?
if( err.message.indexOf("ECONNREFUSED") > -1 )
{
//Safer to shut down instead of ignoring
//See: http://shapeshed.com/uncaught-exceptions-in-node/
console.error("Waiting for CLI connection to come up. Restarting in 2 second...");
setTimeout(shutdownProcess, 2000);
}
else
{
//This is some other exception..
console.error('uncaughtException: ' + err.message);
console.error(err.stack);
shutdownProcess();
}
});
//Desc: Restarts the process. Since forever is managing this process it's safe to shut down
// it will be restarted. If we ignore exceptions it could lead to unstable behavior.
// Exit and let the forever utility restart everything
function shutdownProcess()
{
process.exit(1); //exit with error
}
You should actually try to prevent the ECONNREFUSED exception from becoming uncaught:
var request = require( 'request' );
app.all( '/proxy/*', function( req, res ){
req.pipe( request({
url: config.backendUrl + req.params[0],
qs: req.query,
method: req.method
}))
.on('error', err => {
const msg = 'Error on connecting to the webservice.';
console.error(msg, err);
res.status(500).send(msg);
})
.pipe( res );
});
If you get an actual uncaught exception, then you should just let the application die.