8

I'm building a example website using Express and I hit something I don't quite understand.
Error-handling middleware(s) should be last one(s) in the pipeline, if I understand correctly. For example, works just fine:

var http = require('http');
var express = require('express');

var app = express();
app.set('view engine', 'jade');
app.set('views', './views');

app.use(express.static('./public'));
http.createServer(app).listen(portNumber, function() { });

app.get('/hello', function(req, res) {
    res.send('Welcome!');
});

app.use(function(err, req, res, next) {
    res.status(500).send('something broke!');
});

app.get('/error', function(req, res, next) {
    somethingNonExistent(2016);
});

However, if I register that middleware before http.createServer call, but after all other middlewares were registered, it won't work - my code isn't called:

var http = require('http');
var express = require('express');

var app = express();

app.use(express.static('./public'));

app.use(function(err, req, res, next) {
    res.status(500).send('something broke!');
});

http.createServer(app).listen(portNumber, function() { });

app.get('/hello', function(req, res) {
    res.send('Welcome!');
});

app.get('/error', function(req, res, next) {
    somethingNonExistent(2016);
});

What did I miss here? My guess is that app.get calls use some middleware internally and it gets messed up.
I use Express 3.2.6 and Node.js 0.10.29, if that makes any difference

6
  • 2
    please comment on the downvotes Commented Jan 31, 2016 at 12:01
  • I'm not sure about the downvotes, but what stopped me from taking any time to answer is the irrelevant extra code. The best way to get an answer is to post the most simplistic use case you can come up with, not post your entire app. Nobody really enjoys debugging, let alone debugging someone else's code. You don't need console logging the port, setting environment configs, math to calculate the length of a day, etc. var app = express();app.use(something); app.get("/hello",...); /*your attempt at error handling*/ Commented Feb 5, 2016 at 15:27
  • @cdbajorin point taken. I'll update the post Commented Feb 6, 2016 at 8:08
  • @chester89 createServer was deprecated some time ago. See the Express documentation for a basic example (expressjs.com/en/starter/hello-world.html) Commented Feb 6, 2016 at 8:22
  • @chester89 Worth noting that in Express 4 the error doesn't get handled in both cases Commented Feb 6, 2016 at 8:38

2 Answers 2

4
+100

When you define routes/middleware, the path you specify is used to see if it matches with incoming requests. Your request will always be routed to the first match. A request might have multiple matches, so order matters here. You can hit the next matching route/middleware by calling the next() function.

When you mount middleware using app.use without specifying a path, every path is eligible to hit that middleware. So, if it's the first thing you mount, every request will use that middleware.

If you want a catch all error handler, you'll want the opposite - you should mount middleware at the very end of your route definitions. You'll need to call the next function in your handler to actually reach this middleware:

app.get('/hello', function(req, res, next) {
  ...
  // Let's pretend that there was some error
  next()
});

// After all of your route definitions...
app.use(function(req, res) {
  res.status(500).send('something broke!');
})

Note that if no route exists for the current path, you will also hit this catch all middleware.

Sign up to request clarification or add additional context in comments.

1 Comment

also, I suspect your answer applies for both versions 3 and 4? just curious
1

Docs

http://expressjs.com/en/guide/error-handling.html

You define error-handling middleware last, after other app.use() and routes calls; for example:

var bodyParser = require('body-parser');
var methodOverride = require('method-override');

app.use(bodyParser());
app.use(methodOverride());
app.use(function(err, req, res, next) {
  // logic
});

The Internal

For ease of understanding, you can imagine the pipeline. When your controller receives a request, inside Express, it looks like this

try {
  fn(req, res, next); // your controller
} catch (err) {
  next(err);
}

So, then your code throw error, it will call next with err. Basically, it's the same as call next(new Error()). After that, express trying to find next middleware with 4 arguments in middleware pipeline. In your situation error handler declared before your shady controller, so he doesn't involved.

Technically, there is no difference between the controller and middlewares. Optionally you can pass in the controller next parameter , and call it to pass through the pipeline further. If you don't call next(), you finish processing the request.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.