概要
あるサーバ用のライブラリを使ったときにrouting後にmiddlewareを挟む必要が出てきました。
そのときに幾つかハマったことがあったので、それをまとめます。
環境
- Node.js 6.6.0
- Express 4.13.4
Express4のミドルウェアの流れ
まずはミドルウェアの実行順について検証します。
const app = require('express')(); let log = ''; app.use(function(req, res, next) { log = 'A' next(); }); app.use(function(req, res, next) { log += 'B' next(new Error("Error!")); }); app.use(function(err, req, res) { log += 'C' res.send("response 1:" + log); }); app.use(function(err) { log += 'D' res.send("response 2:" + log); }); app.use(function(err, req, res, next) { log += 'E' res.send("response 3:" + log); }); app.listen(3000);
結果
response 3:ABE
ポイント
今回のポイントは以下です。
next()
が呼ばれると次のapp.use(function(req, res, next) {})
に進むnext(err)
が呼ばれると次のapp.use(function(err, req, res, next) {})
に進む- 上2つの区別は引数の数に依る。
next()
は3つ以下。next(err)
は4つのミドルウェアへ進む throw err
の場合もapp.use(function(err, req, res, next) {})
に進む
これらを理解していると上記の結果になったことも納得がいきますね。
routingの後のmiddleware
先ほどの話を踏まえてroutingの後にmiddlewareを置きます。
NG
const app = require('express')(); let log = ''; app.use(function(req, res, next) { log = 'A' next(); }); app.get('/', function(req, res) { log += 'B' res.send("response 1:" + log); }); app.use(function(req, res, next) { log += 'C' console.log(log) next() }); app.use(function(err, req, res, next) { log += 'D' console.log(log) }); app.listen(3000);
この結果は
response 1:AB
となるだけでconsole.logは出力されません。
OK
const app = require('express')(); let log = ''; app.use(function(req, res, next) { log = 'A' next(); }); app.get('/', function(req, res, next) { log += 'B' res.send("response 1:" + log); next(); }); app.use(function(req, res, next) { log += 'C' console.log(log) next() }); app.use(function(err, req, res, next) { log += 'D' console.log(log) }); app.listen(3000);
結果は
response 1:AB
console.logは
ABC
と表示されます。
ポイント
ここで注意する点は以下です。
- routingの最後に
next()
を呼ぶ - res.send()を呼んだのでレスポンスはすでに返している
- 上記の理由から、後からレスポンスを変更することはできない
まとめ
next()
・next(err)
の違い、レスポンスが返るタイミングに注意すると大丈夫ですね。