I have some proxy code like this below. Problem is that whenever the target server is down, this code fails to capture the error, resulting in the entire application crashing with Error: connect ECONNREFUSED.
For a proxy server, this is terrible, it needs to just return an error to the caller, not crash altogether upon the first time that the target server is unreachable.
What is the right way around it these days?
Node version 6.
let targetUrl = "http://foo.com/bar"
app.options('/cors-proxy/bar', cors())
app.post('/cors-proxy/bar', function(req, res) {
console.log(`received message with method ${req.method} and some body ${req.body}`)
console.log(`relaying message to ${targetUrl}`)
try {
req.pipe(
request({
url: targetUrl,
method: req.method,
json: req.body
})
).pipe(res);
} catch (err) {
res.status(502)
res.render('error', {
message: err.message,
error: err
});
}
});
Thanks!
In general, you can't use try/catch to catch exceptions that may occur in asynchronous callbacks or asynchronous operations. That will only catch synchronous errors.
Instead, you have to read how each particular asynchronous operation reports errors and make sure you are plugged into that particular mechanism.
For example, streams report errors with a message to the stream that you intercept with stream.on('error', ...). For example, a request() can report errors several different ways depending upon which request() library you are actually using and how you are using it.
Some references:
Error handling with node.js streams
Stream Readable Error
How Error Events Affect Piped Streams in Node.js
Related
I'm using a few external API's (some in timers, every minute or so) and sometimes I get some connection errors because of network problems or because the external systems are down for some reason. When I get this errors, the app restarts, and if the error persists the app continues restarting.
Any ideas on how can I ignore the connection error and keep the app running?
Code Example:
try {
var req = https.request(options, callback);
req.write(JSON.stringify(params));
req.end();
} catch (e) {
throw e;
}
Based on your code example. You're doing throw e inside your try catch. Essentially, you're catching an error and then throwing the error. Just do console.error(err) or however you want to handle that error, without throwing. This is what will cause your instance to stop.
I'm writing a node.js web service which needs to communicate with another server. So its basically server to server communication. I don't have any previous experience of writing web services so I have very limited knowledge. For unit tests I'm using Mocha.
Now, I intend to test the behavior of my service for a particular scenario when this other server doesn't respond to my GET request and the request is actually timed out. For tests I've created a fake client and server around my web service. My web service now takes request from this fake client and then gets information from another fake server that I created which then returns the response in the expected format. To simulate timeout I don't do response.end() from my route handler. The problem is that Mocha judges it to have failed this test case.
Is there a way I could catch this intentional timeout in Mocha and the test is a success?
As mido22 suggested you should use handle the timeout generated by whatever library you use to connect. For instance, with request:
var request = require("request");
it("test", function (done) {
request("http://www.google.com:81", {
timeout: 1000
}, function (error, response, body) {
if (error && error.code === 'ETIMEDOUT') {
done(); // Got a timetout: that's what we wanted.
return;
}
// Got another error or no error at all: that's bad!
done(error || new Error("did not get a timeout"));
});
});
app.get('/', function(req, res) {
doSomethingAsync(function(err) {
throw new Error('some unexpected/uncaught async exception is thrown');
})
})
Possibly unhandled Error: some unexpected/uncaught async exception is thrown
at ...stacktrace...:95:9
From previous event:
at ...stacktrace...:82:6)
at ...stacktrace...:47:6)
at ...stacktrace...:94:18)
I have tried a bunch of domain middlewares however they all only work for express 3. I am currently on express 4.5 and I am wondering if express had changed that domain no longer works.
Currently, when an exception is thrown, the response basically hangs until a timeout.
assume the error you got is inside router or controller
put this in very end of your app configuration, before listening
app.use(function(err, req, res) {
res.status(err.status || 500);
// if you using view enggine
res.render('error', {
message: err.message,
error: {}
});
// or you can use res.send();
});
your app will catch any uncaught router error and will render "error" page
by the way do not forget to include "next" in your router Initialization
Edited
app.get('/', function(req, res, next) {
try {
signin(req.query.username, req.query.password, function(d){
if (d.success) {
req.session.user = d.data;
}
res.end(JSON.stringify(d));
});
} catch(e) {
next(e);
}
}
Hope it help
As you have found, trying to try/catch an asynchronous function doesn't work. Domains should work just fine in express 4 (or express 3, or straight http, whatever). I've never used any express middleware that attempts to implement domain handling though, so I can't really speak to how well they do or don't work.
I'd suggest just implementing domain handling on your own; it's not that bad. One of the better examples of using domains is right in node's documentation on domains (not the first bad example they show, the second, good one). I strongly recommend reading those docs.
The basic idea is pretty simple:
Create a domain
Add an error handler
Call domain.run(function() { ... }) putting the code you want inside the domain in that run callback.
An extremely simple (and very localized) example:
// This will alwas throw an error after 100ms, but it will still
// nicely return a 500 status code in the response.
app.get('/', function(req, res) {
var d = domain.create();
d.on('error', function(err) {
res.status(500).send(err.message);
});
d.run(function() {
setTimeout(function() {
throw new Error("some unexpected/uncaught async exception");
}, 100);
});
});
So, that will work and it might be enough for your case, but it's not the best solution (If you've read the docs, you might notice that it's pretty darn close to their bad example). The problem is (from the docs again):
By the very nature of how throw works in JavaScript, there is almost
never any way to safely "pick up where you left off", without leaking
references, or creating some other sort of undefined brittle state.
The best solution (as far as I'm aware anyway) is to do what's recommended in the node docs. The basic idea that they suggest is to use cluster (or something similar) to start multiple worker processes which run your web server from a master process. In each of those worker processes, setup a domain which will nicely send back a 500 status when an error is thrown and then exit. Then, in the master process, detect when a worker exits and simply start up a new one.
What that does is eliminate any problems with "picking up where you left off" by simply restarting the entire process when there's a thrown error, but only after handling it gracefully.
Putting an example of that in a SO answer is probably a bit much, but there really is a great example right in the node docs. If you haven't already, go take a look at it. :)
I build a server with node.js and Express.
Everything works great, but in some cases the client sends invalid parameter, that I don't predict, and I don't handle with. The result of these requests that my server failed, and can't serve other requests.
For example, In one of my function. I have the next lines:
app.post("/getFile", function (req,res){
// some code...
fs.read(fd, buffer, 0, byteRoRead, start, function(err, bytesRead, buffer){
buffer.pipe(res);
})
})
Because the client sent incorrect start param, my server failed with the next error:
fs.js:457
binding.read(fd, buffer, offset, length, position, wrapper);
^
Error: Offset is out of bounds
So now I can fix it, but there is many other error that I can't predict, so I want to gives a client response of unexpected error, but I want that my server would still alive.
Express has built in error handling as a middleware. See http://expressjs.com/guide.html#error-handling for a more comprehensive guide but as an example:
app.use(function(err, req, res, next){
console.error(err.stack);
res.send(500, 'Something broke!');
});
This middleware would catch the error, log it to the console and return a 500 page to the user. This also will stop the server crashing. If you wanted to log the error, but still let the server crash add throw err; to the body of that function.
This is sometimes a good idea as you may not want the server to continue to serve requests if it is in some unexpected error state. Refer to http://shapeshed.com/uncaught-exceptions-in-node/ as a good brief guide on the subject. Also, see http://www.joyent.com/developers/node/design/errors for a more detailed discussion.
Please note that the above "possible answer" questions does not contain an answer to my question. I am using require("http"). In that question the person is taking a socket input variable that they can put a handler on. I do not have the same variable.
I have a very simple server that I have written in Node.
var http = require("http");
var sys = require("sys");
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
target: "someServer"
});
http.createServer(function(request, response) {
try {
proxy.web(request,response);
} catch (err) {
sys.puts("I caught an error!");
}
}).listen(5000);
When I leave my app running, it crashes. My command line says:
events.js:72
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at errnoException (net.js:900:11)
at TCP.onread (net.js:555:19)
It seems to crash not when server is serving files, but when it is waiting for a long time between requests.
While my code is a little more complex, I do have error catching on every callback.
Why is it crashing? What can I do?
In node, sprinkling try and catch everywhere is not the same as catching every error. (And in most cases, doing so is useless.) Asynchronous operations cannot throw useful exceptions because control long ago left the block of code that invoked the operation.
Instead, many objects emit an error event. The error event is a special case in that node will throw a "real" exception if there are no listeners for the event. Because this exception is thrown from code you do not and cannot control (ie wrap with try/catch), it goes uncaught and the process ends.
So if you do not add an error listener to sockets, a socket error will bring down the entire app.
However, your unhandled error is not coming from your http requests. The http module adds an error handler to every socket automatically, and re-emits the error as a clientError event on the Server. Because EventEmitters only throw when the event is named error, the fact that you don't handle clientError does not matter.
If we read http-proxy's documentation, we see that it also throws an error event, and you aren't listening for it. Thus, your app dies whenever there's an error fetching something from an upstream server.
Add an error handler.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong.');
console.error(err);
});
Any time you see this error ("// Unhandled 'error' event"), it means you need to find out what is emitting an error event and add a listener to handle the error.