Expressに関する情報を探していると、ミドルウェア関数の引数にnextという記述をよく見かけます。具体的には以下のようのな記述です。
app.get('/', (req, res, next){ ・・・・・ });
調べてみると、次のミドルウェアへのコールバック引数ということですが、いまいちピンと来ないので色々試してみました。
next()を利用しないとどうなるかやってみた
ルートに対するgetを複数定義した場合
ルートに対するget要求を複数定義してみました。 app.get('/', (req, res) => { ・・・の部分ですね。それぞれにreturnを持たせ、ログも出力するようにしています。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log('First');
return res.send('First Return');
});
app.get('/', (req, res) => {
console.log('Second');
return res.send('Second Return!');
});
app.listen('3000', () => console.log('Started.'));

PS C:\express-next> node app.js Started. First
クライアントからルートパスに対するGET要求に、上の方に記載したミドルウェアのみ動作しました。ここで要求に対してreturnしているのでSecondの方まで処理は届きません。
Returnを外してみる
それぞれのミドルウェア関数のReturn部分をコメントアウトしてみました。
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log('First');
//return res.send('First Return');
});
app.get('/', (req, res) => {
console.log('Second');
//return res.send('Second Return!');
});
app.listen('3000', () => console.log('Started.'));

PS C:\express-next> node app.js Started. First
結果、コンソールにFirstと出るものの、ブラウザ上はLocalhostからの応答を待つ状態となり、最終的にタイムアウトとなります。要求に対して何も返していないので当然ですね。
next()で次のミドルウェア関数を呼び出す
ではコールバック引数のnextを利用して次のミドルウェア関数を呼び出すようにしてみます。ミドルウェア関数の引数に「next」を追加します。
app.get('/', (req, res, next) => {・・・
そしてconsole.log('First');のあとにnext();を追加してみます。
const express = require('express');
const app = express();
app.get('/', (req, res, next) => {
console.log('First');
next(); // ←追加
return res.send('First Return');
});
app.get('/', (req, res) => {
console.log('Second');
//return res.send('Second Return!');
});
app.listen('3000', () => console.log('Started.'));

First Returnが返ってきました。ログを見ると・・
PS C:\express-next> node app.js Started. First Second
Secondが記録されていますね。next();の部分で次のミドルウェア関数が呼び出されたことが分かるかと思います。
First Returnをコメントアウトし、Second Returnを有効化するとSecond Returnが返ってきます。
First ReturnとSecond Return両方構成する
余談ですが、First RetrunとSecond Retrunを両方有効にしてみます。
const express = require('express');
const app = express();
app.get('/', (req, res, next) => {
console.log('First');
next();
return res.send('First Return');
});
app.get('/', (req, res) => {
console.log('Second');
return res.send('Second Return');
});
app.listen('3000', () => console.log('Started.'));

画面上はSecond Returnが返ってきています。ログを見てみると・・
PS C:\express-next> node app.js Started. First Second Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:470:11) at ServerResponse.header (C:\express-next\node_modules\express\lib\response.js:767:10) at ServerResponse.contentType (C:\express-next\node_modules\express\lib\response.js:595:15) at ServerResponse.send (C:\express-next\node_modules\express\lib\response.js:145:14) at app.get (C:\express-next\app.js:7:16) at Layer.handle as handle_request at next (C:\express-next\node_modules\express\lib\router\route.js:137:13) at Route.dispatch (C:\express-next\node_modules\express\lib\router\route.js:112:3) at Layer.handle as handle_request at C:\express-next\node_modules\express\lib\router\index.js:281:22
エラーが出ました。端的に言うと一度レスポンスを返しているのに、再度レスポンスを返そうとしていますよ、という内容です。
今回のケースでは、Console.log('First');⇒Console.log('Second');⇒return res.send('Second Return');⇒return res.send('First Return');という流れになるために発生します。
まとめ
Expressはリクエストにマッチするミドルウェア関数を上から順に実行します。Nextを利用することで、特定のリクエストに対して次々にミドルウェア関数を呼び出すことが可能となります。
特定条件時のみ次のミドルウェア関数を実行する、など様々な用途があるかと思います。
しっかり使いこなせるようになりたいですね。
コメント