メシのタネ

めしのたねになるIT情報配信サイト


LaravelのMiddlewareって意味あるの?仕組み・使いどころ・やらかしまで整理してみた


  1. Laravel
  2. LaravelのMiddlewareって意味あるの?仕組み・使いどころ・やらかしまで整理してみた

あいつ、Controllerの前でなにかやってるんだけど、
初見だと「なんかよくわからんやつ」くらいの印象しか持てません。

ただ、ルーティングが増えてきたり、認証や制限が必要になってくると、
Middlewareって仕組みをちゃんと知ってるかどうかで、コードの見通しがだいぶ変わってくるので理解しておきたいよくわからんやつになります。

この記事では、Middlewareって何をやってるのか?どこで設定されてるのか?
それから、自分で書くときに何に気をつけたらいいのか、みたいなところを整理してみたいと思います。

Middlewareってなにしてるの?

Laravelでリクエストを受け取るとき、Controllerに直で届くわけじゃなくて、
「Middleware」という通り道を経由してから入ってくる仕組みになってます。

ここでは、ログインチェックをしたり、特定のIPを弾いたり、
メンテナンス中の表示をしたり、「とりあえず中に入る前に一つやらして」みたいなことをまとめてやる。

public function handle(Request $request, Closure $next)
{
    if ($request->ip() === '127.0.0.1') {
        return response('ローカルアクセスは禁止です', 403);
    }

    return $next($request);
}

このMiddlewareは、リクエストが127.0.0.1(ローカル)から来てたら、そこで弾く。
そうじゃなければ、$next($request)で「次の処理(たとえばController)」にバトンを渡す。

$next($request)ってなに?

これは「次のMiddlewareかControllerにリクエストを渡す」って意味。
Laravelは複数のMiddlewareを順番に通していくんで、
それぞれが $next($request) を実行することで、次へと処理が流れていく。

つまり、Middlewareはリクエスト処理のリレー走みたいなもの。
バトンを渡さないと、後ろのやつが動かない。

たねまる

$nextって型見たら Closure になっててびっくりするよね〜。

Middlewareってどこで管理されてるの?

Middlewareって、Controllerの前にあるフィルターですよ、って話を前章でしましたが、
じゃあ「そのフィルター、どこにあるの?」って話をそろそろしないと気持ち悪い。

LaravelはMiddlewareの登録と実行を、ほぼapp/Http/Kernel.phpで管理してます。
このファイル、基本はあんまり触らないけど、裏ではめちゃくちゃ大事なことしてる

class Kernel extends HttpKernel
{
    protected $middleware = [
        // グローバルに適用されるMiddleware
    ];

    protected $middlewareGroups = [
        'web' => [
            // セッション、CSRF、Cookie系など
        ],
        'api' => [
            // API用の制限とか
        ],
    ];

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        // ここで個別に呼べるやつ
    ];
}

この構造が、Middlewareの三層構造みたいなもの。

💡 ざっくり3パターンある

種類どこで使う?いつ動く?
middleware全リクエストに自動で適用常に
middlewareGroupsルートグループ(web, api)ごとに使うweb.php / api.php で分かれる
routeMiddlewareルートやControllerに個別に指定必要なときだけ

例:ルートに個別でミドルウェア指定する

Route::middleware(['auth', 'verified'])->get('/dashboard', [DashboardController::class, 'index']);

このとき、routeMiddleware'auth''verified' が登録されてないと、
「ミドルウェアなんて知らんがな」って怒られる。

Controllerに直接指定するパターンもある:

class DashboardController extends Controller
{
    public function __construct()
    {
        $this->middleware(['auth']);
    }
}
たねまる

Kernel.phpってLaravelくんの指令書みたいなものって考えると親しみでてくるね〜。

自分でMiddleware書くと、何がラクになるの?

Laravelを触ってると、認可チェックや条件分岐をなんとなくControllerの中に書いてること、ありませんか?

たとえばこういうやつっす:

public function index()
{
    if (!auth()->user()?->isAdmin()) {
        return redirect('/');
    }

    // 管理者向けの処理
}

いや、普通ですけど?って思いますよね。
ただ、もしこれをやっているあなたに朗報です。もっとControllerが単純になります🤩

事前チェックをまとめて外に出せるので、Controllerがやるべきことに集中できるようになるんですよ。

public function index()
{
    // もう「管理者であること」は保証されてる状態
    return view('admin.dashboard');
}

もちろんこれをやるためには1章で例に出したようにMiddlewareを指定する必要があります。

指定方法色々あるので、再掲がてら、色々やり方を紹介しましょう。

【再】ルートに直接指定する

Route::middleware(['auth', 'verified'])->get('/dashboard', [DashboardController::class, 'index']);

こういう利用法方法が一般的なんじゃないでしょうか。

ちなみにGroupに対しても適用可能です。

Route::middleware('web')->group(function () {
    Route::get('/home', [HomeController::class, 'index']);
    Route::get('/settings', [SettingsController::class, 'edit']);
});

ちまちまやらないでよくて便利っすね。ちなみにネストも可能。

Route::middleware('auth')->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);

    Route::middleware('admin')->group(function () {
        Route::get('/admin/users', [AdminUserController::class, 'index']);
        Route::get('/admin/settings', [AdminSettingController::class, 'index']);
    });
});

ネストすることで表現力が広がりますな。

Controllerごとに適用

class DashboardController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('verified')->only('index');
    }
}

念の為補足しておくと、middlewareはサービスコンテナん中に入ってるんで、$this->middlewareみたいな波動拳飛び道具使えるんですね。

ぶっちゃけこの指定するくらいだったらRouteに書いた方が賢そうに見えます。

たねまる

Controllerに書くのってなんか潜在バグ産みそうで怖いかも〜。あれ、どこにMiddreware書いたっけ〜って後でならないような仕組みづくりを考えた方がいいかもね〜。

Middleware失敗あるある〜🎉

ここまでMiddlewareの使い方を見てきました。
ここからはおまけで、LaravelのMiddleware実装でやりがちな失敗例を挙げていきます。

Laravelはエラーメッセージが優しすぎて、
“根本の設計のミス”を黙って受け入れてしまう場合があります、Middlewareの使い方も注意が必要。

エラーメッセージが優しい?

優しさ?その1:$next($request) を returnしなくても肯定してくれるから地獄💀

public function handle(Request $request, Closure $next)
{
    $next($request);
    // return 忘れた
}

Laravel:「いいよ、いいよ!return つけ忘れちゃうことあるもんね☺️」
実際にはレスポンス返らず、ここで処理終了(Controllerが動かない)。「明確なエラー」としてLaravelは怒らない

優しさ?その2:routeMiddleware に登録してないMiddlewareをルートで呼ぶ

Route::middleware(['hogehoge'])->get('/dashboard', ...);

Laravel:「あー、hogehogeってMiddlewareは無いんだよね〜。でもそれ作ってないっていうのもユーザーさんに悪いしなー。」
Class not found って言われるけど、“Middleware名のミスだよ”って教えてはくれない。

上記を踏まえた上であるあるいきます。

$next($request)後に処理を書くのを忘れる

public function handle(Request $request, Closure $next)
{
    $next($request);
    
    // この処理、実行されません
    Log::info('after request');
}

returnを忘れると、値が消える。
“実行はされるけどレスポンス返さないやつ”になって、⚪︎ぬ💀

❌ Middlewareの順番を気にしない

protected $middlewareGroups = [
    'api' => [
        \App\Http\Middleware\CheckRateLimit::class,
        \App\Http\Middleware\Authenticate::class,
    ],
];

順番が逆だと、「認証前にレート制限」とかいう意味不明な処理順になることがある。
Middlewareって“上から順に通る”だけなんで、意図しない構成にすると挙動バグる。

たねまる

Laravelくん優しすぎて、だいたい黙って通してくれるんだよね〜。

Middlewareってどんなときに使うといい?

ここまでMiddlewareの仕組みや使い方を見てきましたが、
最後にMiddlewareの使いどきでも置いといて終わろうと思います。

Middleware向きの処理

処理内容使いどころ
認証チェックauthミドルウェアでログイン済みかを確認
ロールチェック管理者だけ通したいエリアなど
IP制限特定のIPだけ許可したいAPIなど
メンテナンス表示アプリ全体または一部にメンテナンス表示を入れる
リクエストログ出力どのルートにどんなアクセスが来てるかログに残す
APIキー検証外部連携の入口で認証処理を挟む
CORS対応APIで必要なヘッダーの付け足しやオリジン制限
レート制限(throttle)APIなどで同一IPからのアクセスを制限

🛠 具体的な判断ポイント

  • ✅ 「この処理、複数のルートで必要なんだけど…」
     → Middlewareに出すと再利用しやすい
  • ✅ 「Controllerが条件分岐まみれになってきた…」
     → ロジックをMiddlewareに逃がして責務を分ける
  • ✅ 「ルートを見ただけで、何が必要かわかるようにしたい」
     → Middlewareで必要な条件を外から見えるようにする

💡 Laravelくん的な推奨設計(実装のポイント)

  • Controllerに書くより、“通過条件”はMiddlewareで書いた方が整理しやすい
  • Kernelで定義 → ルートに適用 → 実装は分離、って流れを覚えておけば、だいたい困らない
  • Middlewareはコードの“入り口”の管理。フロントでいうところの「画面に来る前のバリデーション」みたいな感覚でOK

以上です。あざした。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.

若い頃、「仕事中にハマったこと」や「誰かに共有したい技術的な気づき」をアウトプットしたくてブログを始めましたが、勢い任せでよく分からない記事を大量生産し、あえなく飽きて終了。

改めて今、キャリア15年分の経験や知識が、これからITエンジニアを目指す方や、同じような課題で悩んでいる現役エンジニアの「メシのタネ」になるような記事を残したいと思っています。
※過去の記事は見ると精神が崩壊するため、そっとしておいてください。

🛠 経歴という名の珍道中:
文系Fラン → 広告営業 → Web営業 → 通信営業 → Web進行 → 出版 → Web媒体運用 → ソフトウェアハウス → SES → フリーランス

専門教育も受けず、転職歴も多数。履歴書はまるで時系列の事故記録のようですが、試行錯誤を重ね、なんとかエンジニアとして食べています。

このブログでは、そんな「履歴書クラッシャー型エンジニア」が送る、
名古屋一敷居の低い、実務に役立つ技術ブログを目指します。

Laravel
LaravelのMiddlewareって意味あるの?仕組み・使いどころ・やらかしまで整理してみたNew!!
Laravel
ServiceProviderって何してるの?DIの背後で動いてるやつの正体New!!
Laravel
LaravelのサービスコンテナとDI、「書いてるだけで動く」コードの正体New!!
Laravel
Laravelのアーキテクチャ、実は誰もわかってない説New!!
ガジェット
【解説】Bluetoothヘッドホンでマイクが使えない理由と回避策まとめ(Mac対応)New!!
Laravel
Laravel Collection入門: mapとeachの違い、ちゃんと説明できますか?