※本記事は「RailsからLaravelを眺める」シリーズの第11回です。Rails出身の私がLaravelを触りながら、Railsと比較して違いを整理していく連載になります。
はじめに
Rails出身のエンジニアがLaravelを触ると、最初に違和感を覚えるのは「同じ用語なのに指しているものが全然違う」という場面です。
その代表例が「ミドルウェア」。
Railsにおけるミドルウェアは「Rack Middleware」であり、RubyのWebフレームワーク共通の基盤です。
一方、Laravelのミドルウェアはフレームワークに密接に統合された仕組みで、ルート単位での認証やCSRF保護、後処理までを担います。
この記事ではまず「結論=抽象化レベルが違う」という点を提示し、その上で特徴の比較、コード例、そして5つの主要な違いを整理していきます。
結論から言うと:抽象化レベルが違う
最初に核心を言ってしまうと、LaravelのミドルウェアとRackは抽象化のレベルが根本的に異なります。
- Rack: Rubyのウェブサーバーとフレームワークをつなぐインターフェース仕様
- Laravelミドルウェア: Laravelフレームワーク内部のHTTPリクエスト処理機構
Rackは「RailsでもSinatraでもHanamiでも使える」共通基盤。
LaravelミドルウェアはLaravel専用で、フレームワークの一部として強く統合されています。
特徴の比較
Rackの特徴
envという生のハッシュでHTTP情報を扱う- 戻り値は
[status, headers, body]の配列 - フレームワークに依存しない汎用的な設計
Laravelミドルウェアの特徴
Request/Responseというリッチなオブジェクトを扱うClosure $nextでパイプライン的に処理を繋ぐ- Laravel専用(他のPHPフレームワークでは利用できない)
コード例(Rack)
# app/middleware/hello_middleware.rb
class HelloMiddleware
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
headers['X-Hello'] = 'World'
[status, headers, body]
end
end
# config/application.rb
Rails.application.config.middleware.use HelloMiddleware
コード例(Laravel)
// app/Http/Middleware/CheckToken.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckToken
{
public function handle(Request $request, Closure $next)
{
if ($request->header('X-TOKEN') !== 'secret') {
return response('Unauthorized', 401);
}
return $next($request);
}
}
登録と適用例:
// app/Http/Kernel.php
protected $routeMiddleware = [
'check.token' => \App\Http\Middleware\CheckToken::class,
];
// routes/web.php
Route::get('/admin', fn () => 'Admin Page')->middleware('check.token');
Terminable Middleware
Laravelには「レスポンス送信後に処理を続行できる」Terminable Middlewareという仕組みがあります。
// app/Http/Middleware/LogAfterResponse.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class LogAfterResponse
{
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
public function terminate(Request $request, Response $response): void
{
\Log::info('Request finished at: ' . now());
}
}
RailsのRack Middlewareには標準で「レスポンス後フック」が存在せず、この点はLaravel独自の強みです。
5つの主な違い
1. インターフェースの違い
- Rackは
call(env)を受け取り、[status, headers, body]を返すシンプルな仕様。 - Laravelは
Request/Responseのオブジェクトを使い、Closure $nextでパイプラインを構築する。
2. 適用範囲の柔軟性
- Rackは基本的に全体に適用される。
- Laravelは全体・グループ・ルート単位で柔軟に適用できる。
3. Railsでの実際の使い分け
Railsではミドルウェア的な処理は二層構造になっています。
- Rackミドルウェア(低レベル)
- セッション管理
- 静的ファイル配信
- ロギング
- セキュリティヘッダー
- コントローラのbefore_action(アプリレベル)
- 認証チェック
- 権限確認
- パラメータ検証
Laravelではこれら両方を「Middleware」に寄せられるのが特徴です。
4. 処理の流れの違い
- Rackは「積み上げた処理を順番に実行 → レスポンスを返す」ストレートな流れ。
- Laravelは「パイプライン」として構築され、
$next()で処理が前後にまたがる。
5. 終了可能性(Terminable Middleware)
- Rackにはレスポンス後フックがない。
- LaravelはTerminable Middlewareによって、レスポンス後の処理を公式にサポート。
Rails脳から見た感想
Rails脳でLaravelのMiddlewareを見ると、「Rackに書くのは違うな」と思っていた処理がMiddlewareに自然に収まるのが印象的です。
認証や認可といった処理をbefore_actionに寄せがちなRailsに対して、Laravelはミドルウェアとして統合的に扱える。
結果として、コントローラの責務がスッキリしやすい設計になっています。
特にTerminable MiddlewareはRailsにない概念で、「レスポンスを返した後に何かする」処理をフレームワーク標準でサポートしているのは新鮮でした。
開発者体験を意識するLaravelらしい仕組みだと感じます。
まとめ
RailsとLaravelのミドルウェアは、同じ「リクエスト処理にフックを挟む仕組み」でも、その立ち位置が大きく異なります。
- RackはWebサーバーとフレームワークをつなぐ共通仕様。低レベルな処理を担当する。
- LaravelのMiddlewareはLaravel専用。ルート単位で柔軟に適用でき、Terminable Middlewareによるレスポンス後処理まで担う。
言い換えれば、Rackは「抽象化された共通基盤」、Laravel Middlewareは「フレームワークに密着した便利ツール」。
Rails出身者にとっては「Rack = インフラ層、Laravel Middleware = アプリ層+後処理」という理解が最もしっくりきます。
フレームワーク哲学の違いを最も端的に感じられるテーマの一つだと思います。



コメント