Edited at

ExpressのMiddlewareを自作してみる

More than 3 years have passed since last update.

http://expressjs.com/guide/using-middleware.html

expressのmiddlewareに興味がわいたので自作してみます。ですのでまず上記サイトを読むことにしました。


結論

app.use(function (req, res, next) {})

もしくは

app.use router か app.use routers

以下は上記サイトを自分なりに解釈した駄文になります。


Middlewareとは


  • request, response, next を受け取るfunction

  • どんなコードでもいい

  • requestとresponseを変更してよい

  • リクエストを終了してもいい

  • nextを呼びリクエストを続行してもいい

  • リクエストを終了しない場合はnextを必ず呼ぶこと

  • オプションでmiddlewareの対象となるパスを指定できる

  • アプリケーションレベル、ルーターレベル、エラーハンドリング、ビルドイン、サードパティの5種類がある


Application level middleware



  • using app.use()app.VERB()によりexpressインスタンスに紐づけされる。 VERBはgetとか。

全リクエストに紐づけされるmiddlewareの例

// a middleware with no mount path; gets executed for every request to the app

app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});

紐づけるパスを限定する例

// a middleware mounted on /user/:id; will be executed for any type of HTTP request to /user/:id

app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// a route and its handler function (middleware system) which handles GET requests to /user/:id
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});

expressで作成したapp.jsのapp.use('/', routes);の前にとりあえず両方を記述してログを見てみました。

/にアクセスした場合

Time: 1426909974303

/user/3にアクセスした場合

Time: 1426909953812

Request Type: GET

できてますね。app.use('/', routes);より前に記述しないと/にアクセスしても実行されないので気を付けて。

またパスに対してmiddlewareを複数登録できるようです。'/user/:id'のmiddlewareを以下のように変更します。

app.use('/user/:id', function(req, res, next) {

console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});

/user/3にアクセス

Time: 1426910635722

Request URL: /user/3
Request Type: GET

できましたね。あと別にバラバラに書いても問題ないみたいです。

app.use('/user/:id', function(req, res, next) {

console.log('Request URL:', req.originalUrl);
next();
});

app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});

注意点は途中でsendするmiddlewareなどリクエストを終了するmiddlewareがあると以降のmiddlewareは実行されない点です。


app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
});

app.get('/user/:id', function (req, res, next) {
res.send('USER');
});

//実行されない
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});

/user/3にアクセス

Time: 1426910635722

Request URL: /user/3

連続して書いた場合、middlewareはシリーズとして扱われます。この利点はシリーズの途中で実行を中止し、次の他のmiddlewareへ移行できる点です。ただしgetなどのVERBメソッドを使用する必要があります。

app.get('/user/:id', 

function(req, res, next) {
console.log('One in Middleware Series:');
next();
},
function(req, res, next) {
console.log('Two in Middleware Series::');
next('route');
},
function(req, res, next) {
console.log('Three but never run');
next();
}
);

app.get('/user/:id', function (req, res, next) {
console.log('Another Middleware:');
next();
});

app.get('/user/:id', function (req, res, next) {
res.send('USER');
});

実行結果

One in Middleware Series:

Two in Middleware Series::
Another Middleware:


Router level middleware

express.Router()に紐づけされる以外はアプリケーションレベルと同じようです。


Error-handling middleware

他と異なり4つの引数を持ちます。

(err, req, res, next)

試しにエラーを強制的に発生させてみます。

app.get('/user/:id', function (req, res, next) {

throw new Error("err")
res.send('USER');
});

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

ブラウザ画面 Something broke!

コンソール

Error: err

at app.use.err.status (/home/ubuntu/workspace/express/demo/app.js:54:9)
at Layer.handle [as handle_request] (/home/ubuntu/workspace/express/demo/node_modules/express
...

できましたね。

詳しくはhttp://expressjs.com/guide/error-handling.html を参照とのことです。


Built-in middleware

4系からsessionなどの過去に組み込まれていたmiddlewareは全て分離したそうです。ただし静的ファイルを扱う express.staticだけは組み込まれているようです。


Third-party middleware

Expressは最小構成だから必要ならサードパティのミドルウェアで機能追加してねみたいな話でした。


まとめ

app.use(function (req, res, next) {})できればmiddleware作れる。最後まで読む必要なかったな!!

実際つくってみるとRouter返したほうがやりやすいかも。用途によるかな?