Help us understand the problem. What is going on with this article?

express4でErrorが起きた後の制御の話

More than 5 years have passed since last update.

express は、app.use()app.VERB() などを使って、
URLのパスに合わせて、必要なミドルウェアを設定していくが、
途中でエラーが起きた場合にcallback関数の第1引数に
next(new Error("Error")) とエラーを入れるようになっている。

ただ、エラーが起きた後に設定したミドルウェアの引数の数によって挙動が変わる。

app.js
var app = require('express')();
var text = '';

app.use(function(req, res, next) {
  text = 'A'
  next();
});

app.use(function(req, res, next) {
  text += 'B'
  next(new Error("Error!"));
});

app.use(function(err, req, res) {
  text += 'C'
  res.send("RESULT 1:" + text);
});

app.use(function(err) {
  text += 'D'
  res.send("RESULT 2:" + text);
});

app.use(function(err, req, res, next) {
  text += 'E'
  res.send("Result 3:" + text);
});

app.listen(3000);

この場合、httpアクセスをした場合
結果は Result 3:ABE になる。

なぜ実行されない関数があるのか

これは、途中でエラーが発生した場合に、このミドルウェアのcallbackの挙動が変わるため。

ミドルウェアは、Layer というlayerオブジェクトを積み重ねて、
httpリクエスト毎に処理が必要かどうかをチェックをしている。

https
proto.use = function(route, fn){
  // 省略…
  var layer = new Layer(route, {
    sensitive: this.caseSensitive,
    strict: this.strict,
    end: false
  }, fn);

  // add the middleware
  debug('use %s %s', route || '/', fn.name || 'anonymous');

  this.stack.push(layer);

Layer のコンストラクタはこんな感じ。

https
function Layer(path, options, fn) {
  if (!(this instanceof Layer)) {
    return new Layer(path, options, fn);
  }

  debug('new %s', path);
  options = options || {};
  this.regexp = pathRegexp(path, this.keys = [], options);
  this.handle = fn;
}

fn が、app.use() などで慣例的に reqresnext を渡す関数を指していて、layer.handle に設定されている。

この関数がパスなどのマッチングに合わせて、順番に実行されていく。
実際にこれが実行されるのが以下になる。

https
      var arity = layer.handle.length;
      if (err) {
        if (arity === 4) {
          layer.handle(err, req, res, next);
        } else {
          next(err);
        }
      } else if (arity < 4) {
        layer.handle(req, res, next);
      } else {
        next(err);
      }

err が入っている場合は、引数が4つでなければ、layer.handle() が呼ばれずにnext(err) が呼び出される。
なので、最初の例では CD は呼び出されない。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away