3秒でわかる
リクエストが本処理に届く前と、応答が返る途中に割り込ませる共通処理。ログや認証チェックを各処理へ書き写さず、1 か所にまとめておくために使います。
もう少し詳しく
どういうものか
Web フレームワークにおけるミドルウェアは、受け取ったリクエストと最終的な処理の間に挟まる関数です。リクエストを見て手を加え、問題なければ次へ渡し、まずければそこで応答を返して打ち切ります。関数が数珠つなぎになっていて、上から順に通っていくイメージです。
Express なら (req, res, next) を受け取る関数がそれにあたります。next() を呼ぶと次のミドルウェアへ進み、呼ばなければそこで流れが止まります。
なぜ必要か
ログイン確認、アクセスログ、リクエストボディの解析といった処理は、ほぼ全部の画面で必要になります。これを個々の処理に書くと、20 画面あれば 20 か所に同じコードが並び、修正のたびに全部直すことになります。ミドルウェアとして手前に置けば、書くのは 1 回で済み、付け外しも 1 行です。
具体例
const express = require("express");
const app = express();
// 全リクエストの所要時間を記録する
<a href="/glossary/app-use" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">app.use</a>((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
console.log(req.method, req.url, Date.now() - start, "ms");
});
next();
});
// 管理画面だけログインを必須にする
function requireLogin(req, res, next) {
if (!req.headers.authorization) {
return res.status(401).json({ error: "ログインが必要です" });
}
next();
}
app.get("/admin", requireLogin, (req, res) => {
res.json({ ok: true });
});つまずきやすいところ
いちばん多いのが next() の呼び忘れです。エラーも出ず、ブラウザがずっと読み込み中のまま固まります。処理が返ってこないときは、途中のミドルウェアで流れが止まっていないかを疑います。
登録の順番も落とし穴です。app.use は書いた順に実行されるため、ボディを解析するミドルウェアより前に置いた処理では req.body がまだ空です。また、応答を返した後に next() も呼ぶと二重送信になり、ヘッダー送信済みのエラーが出ます。
似た用語との違い
同じ「ミドルウェア」でもインフラ分野では、OS とアプリの間に入るデータベースやアプリケーションサーバーなどの製品群を指します。文脈が全く違うので、求人票や設計書で出てきたときはどちらの意味かを先に確かめます。
覚え方
空港の保安検査を思い浮かべます。搭乗口 (本処理) に着く前に、全員が同じ検査場を順番に通ります。