본문 바로가기

미들웨어

번역일: 2026년 6월 20일

미들웨어

소개

미들웨어는 애플리케이션으로 들어오는 HTTP 요청을 검사하거나 필터링하는 편리한 메커니즘입니다. 예를 들어, Laravel에는 사용자가 인증되어 있는지 확인하는 미들웨어가 내장되어 있습니다. 인증되지 않은 사용자라면 로그인 페이지로 리다이렉트하고, 인증된 사용자라면 요청을 애플리케이션 내부로 통과시킵니다.

인증 외에도 다양한 목적으로 미들웨어를 작성할 수 있습니다. 예를 들어 로깅 미들웨어는 모든 요청을 기록할 수 있습니다. Laravel에는 인증, CSRF 보호 등 여러 미들웨어가 기본으로 포함되어 있으며, 개발자가 직접 작성한 미들웨어는 보통 app/Http/Middleware 디렉터리에 위치합니다.

미들웨어는 HTTP 요청이 애플리케이션에 도달하기 전에 통과해야 하는 일련의 "관문"으로 생각하면 이해하기 쉽습니다. 각 관문은 요청을 검사하고, 필요하다면 거부할 수도 있습니다.

미들웨어 정의하기

새 미들웨어를 생성하려면 make:middleware Artisan 명령어를 사용합니다:

php artisan make:middleware EnsureTokenIsValid

이 명령어를 실행하면 app/Http/Middleware 디렉터리에 EnsureTokenIsValid 클래스가 생성됩니다. 아래 예시에서는 요청의 token 입력값이 지정된 값과 일치할 때만 라우트에 접근을 허용하고, 그렇지 않으면 /home으로 리다이렉트합니다:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class EnsureTokenIsValid { /** * 들어오는 요청을 처리합니다. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { if ($request->input('token') !== 'my-secret-token') { return redirect('/home'); } return $next($request); } }

token 값이 일치하지 않으면 클라이언트를 리다이렉트하고, 일치하면 $next($request)를 호출해 요청을 다음 단계로 전달합니다. $next 콜백을 호출하는 것이 미들웨어를 "통과"시키는 방법입니다.

NOTE

모든 미들웨어는 서비스 컨테이너를 통해 해석됩니다. 따라서 미들웨어의 생성자에서 필요한 의존성을 타입힌트로 주입받을 수 있습니다.

요청 전처리와 후처리

미들웨어는 요청이 애플리케이션에 전달되기 또는 에 작업을 수행할 수 있습니다.

아래는 요청이 처리되기 전에 작업을 수행하는 미들웨어입니다:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class BeforeMiddleware { public function handle(Request $request, Closure $next): Response { // 요청 처리 전 작업 수행 return $next($request); } }

반면, 아래는 요청이 처리된 후에 작업을 수행하는 미들웨어입니다:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class AfterMiddleware { public function handle(Request $request, Closure $next): Response { $response = $next($request); // 응답 반환 전 작업 수행 return $response; } }

미들웨어 등록하기

전역 미들웨어

모든 HTTP 요청마다 실행되어야 하는 미들웨어는 bootstrap/app.php 파일의 전역 미들웨어 스택에 추가합니다:

use App\Http\Middleware\EnsureTokenIsValid; ->withMiddleware(function (Middleware $middleware) { $middleware->append(EnsureTokenIsValid::class); })

withMiddleware 클로저에 전달되는 $middleware 객체는 Illuminate\Foundation\Configuration\Middleware 인스턴스로, 애플리케이션의 미들웨어를 관리합니다. append 메서드는 미들웨어를 전역 스택의 맨 끝에 추가하고, prepend 메서드는 맨 앞에 추가합니다.

Laravel 기본 전역 미들웨어 직접 관리하기

전역 미들웨어 스택을 완전히 직접 관리하고 싶다면, use 메서드에 원하는 미들웨어 목록을 직접 지정할 수 있습니다:

->withMiddleware(function (Middleware $middleware) { $middleware->use([ \Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class, // \Illuminate\Http\Middleware\TrustHosts::class, \Illuminate\Http\Middleware\TrustProxies::class, \Illuminate\Http\Middleware\HandleCors::class, \Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Http\Middleware\ValidatePostSize::class, \Illuminate\Foundation\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, ]); })

라우트에 미들웨어 적용하기

특정 라우트에만 미들웨어를 적용하려면 라우트 정의 시 middleware 메서드를 체이닝합니다:

use App\Http\Middleware\EnsureTokenIsValid; Route::get('/profile', function () { // ... })->middleware(EnsureTokenIsValid::class);

여러 미들웨어를 적용할 때는 배열로 전달합니다:

Route::get('/', function () { // ... })->middleware([First::class, Second::class]);

특정 라우트에서 미들웨어 제외하기

라우트 그룹에 미들웨어를 적용했더라도, 그룹 내 특정 라우트에서만 해당 미들웨어를 제외하고 싶을 때는 withoutMiddleware 메서드를 사용합니다:

use App\Http\Middleware\EnsureTokenIsValid; Route::middleware([EnsureTokenIsValid::class])->group(function () { Route::get('/', function () { // ... }); Route::get('/profile', function () { // ... })->withoutMiddleware([EnsureTokenIsValid::class]); });

라우트 그룹 전체에서 미들웨어를 제외할 수도 있습니다:

use App\Http\Middleware\EnsureTokenIsValid; Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () { Route::get('/profile', function () { // ... }); });

NOTE

withoutMiddleware 메서드는 라우트 미들웨어만 제거할 수 있으며, 전역 미들웨어에는 적용되지 않습니다.

미들웨어 그룹

여러 미들웨어를 하나의 키로 묶어 라우트에 편리하게 적용하고 싶을 때 미들웨어 그룹을 활용합니다. bootstrap/app.php 파일에서 appendToGroup 또는 prependToGroup 메서드로 그룹을 정의할 수 있습니다:

use App\Http\Middleware\First; use App\Http\Middleware\Second; ->withMiddleware(function (Middleware $middleware) { $middleware->appendToGroup('group-name', [ First::class, Second::class, ]); $middleware->prependToGroup('group-name', [ First::class, Second::class, ]); })

미들웨어 그룹은 개별 미들웨어와 동일한 방식으로 라우트에 적용할 수 있습니다:

Route::get('/', function () { // ... })->middleware('group-name'); Route::middleware(['group-name'])->group(function () { // ... });

Laravel 기본 미들웨어 그룹

Laravel은 웹 라우트와 API 라우트에 자주 사용하는 미들웨어를 묶은 webapi 그룹을 기본으로 제공합니다. 이 그룹은 각각 routes/web.phproutes/api.php 파일에 자동으로 적용됩니다:

web 미들웨어 그룹
Illuminate\Cookie\Middleware\EncryptCookies
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
Illuminate\Session\Middleware\StartSession
Illuminate\View\Middleware\ShareErrorsFromSession
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
Illuminate\Routing\Middleware\SubstituteBindings
api 미들웨어 그룹
Illuminate\Routing\Middleware\SubstituteBindings

기본 그룹에 미들웨어를 추가하거나 앞에 삽입하려면 web, api 메서드를 사용합니다. 이 메서드들은 appendToGroup의 편리한 대안입니다:

use App\Http\Middleware\EnsureTokenIsValid; use App\Http\Middleware\EnsureUserIsSubscribed; ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ EnsureUserIsSubscribed::class, ]); $middleware->api(prepend: [ EnsureTokenIsValid::class, ]); })

기본 그룹의 특정 미들웨어를 커스텀 미들웨어로 교체할 수도 있습니다:

use App\Http\Middleware\StartCustomSession; use Illuminate\Session\Middleware\StartSession; $middleware->web(replace: [ StartSession::class => StartCustomSession::class, ]);

또는 특정 미들웨어를 완전히 제거할 수 있습니다:

$middleware->web(remove: [ StartSession::class, ]);

Laravel 기본 미들웨어 그룹 직접 관리하기

webapi 그룹의 미들웨어 목록 전체를 직접 관리하고 싶다면 그룹을 완전히 재정의할 수 있습니다:

->withMiddleware(function (Middleware $middleware) { $middleware->group('web', [ \Illuminate\Cookie\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, ]); $middleware->group('api', [ // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, // 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ]); })

NOTE

기본적으로 webapi 미들웨어 그룹은 bootstrap/app.php에 의해 각각 routes/web.phproutes/api.php에 자동으로 적용됩니다.

미들웨어 별칭

클래스명이 긴 미들웨어를 라우트에서 사용할 때 짧은 별칭을 지정하면 편리합니다. bootstrap/app.php 파일에서 alias 메서드로 별칭을 등록합니다:

use App\Http\Middleware\EnsureUserIsSubscribed; ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'subscribed' => EnsureUserIsSubscribed::class ]); })

별칭을 등록하면 라우트에서 짧은 이름으로 미들웨어를 적용할 수 있습니다:

Route::get('/profile', function () { // ... })->middleware('subscribed');

Laravel은 자주 사용되는 내장 미들웨어에 대해 기본 별칭을 제공합니다:

별칭미들웨어
authIlluminate\Auth\Middleware\Authenticate
auth.basicIlluminate\Auth\Middleware\AuthenticateWithBasicAuth
auth.sessionIlluminate\Session\Middleware\AuthenticateSession
cache.headersIlluminate\Http\Middleware\SetCacheHeaders
canIlluminate\Auth\Middleware\Authorize
guestIlluminate\Auth\Middleware\RedirectIfAuthenticated
password.confirmIlluminate\Auth\Middleware\RequirePassword
precognitiveIlluminate\Foundation\Http\Middleware\HandlePrecognitiveRequests
signedIlluminate\Routing\Middleware\ValidateSignature
subscribed\Spark\Http\Middleware\VerifyBillableIsSubscribed
throttleIlluminate\Routing\Middleware\ThrottleRequests 또는 Illuminate\Routing\Middleware\ThrottleRequestsWithRedis
verifiedIlluminate\Auth\Middleware\EnsureEmailIsVerified

미들웨어 실행 순서 지정

라우트에 미들웨어를 등록할 때 순서를 직접 제어하기 어려운 상황에서도 특정 실행 순서가 필요하다면, bootstrap/app.php에서 priority 메서드를 사용해 우선순위를 지정할 수 있습니다:

->withMiddleware(function (Middleware $middleware) { $middleware->priority([ \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, \Illuminate\Cookie\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class, \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class, \Illuminate\Auth\Middleware\Authorize::class, ]); })

미들웨어 파라미터

미들웨어는 추가 파라미터를 받을 수 있습니다. 예를 들어, 특정 "역할(role)"을 가진 사용자만 접근을 허용해야 할 때, 역할 이름을 파라미터로 받는 EnsureUserHasRole 미들웨어를 만들 수 있습니다.

추가 파라미터는 $next 인자 다음에 선언합니다:

<?php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class EnsureUserHasRole { /** * 들어오는 요청을 처리합니다. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next, string $role): Response { if (! $request->user()->hasRole($role)) { // 리다이렉트 처리... } return $next($request); } }

라우트 정의 시 미들웨어 이름 뒤에 :를 붙이고 파라미터를 지정합니다:

use App\Http\Middleware\EnsureUserHasRole; Route::put('/post/{id}', function (string $id) { // ... })->middleware(EnsureUserHasRole::class.':editor');

여러 파라미터가 필요하면 쉼표로 구분합니다:

Route::put('/post/{id}', function (string $id) { // ... })->middleware(EnsureUserHasRole::class.':editor,publisher');

종료 가능한 미들웨어

HTTP 응답이 브라우저로 전송된 이후에 추가 작업이 필요한 경우가 있습니다. 예를 들어 세션 데이터를 저장하거나, 응답 후 로깅을 처리하는 경우가 이에 해당합니다. 미들웨어에 terminate 메서드를 정의하고 웹 서버가 FastCGI를 사용하고 있다면, 응답이 전송된 직후 terminate 메서드가 자동으로 호출됩니다:

<?php namespace Illuminate\Session\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class TerminatingMiddleware { /** * 들어오는 요청을 처리합니다. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { return $next($request); } /** * 응답이 브라우저로 전송된 후 작업을 처리합니다. */ public function terminate(Request $request, Response $response): void { // 응답 전송 후 처리 로직 } }

terminate 메서드는 요청($request)과 응답($response) 객체를 모두 전달받습니다. 종료 가능한 미들웨어를 정의했다면 bootstrap/app.php에서 라우트 미들웨어 또는 전역 미들웨어로 등록해야 합니다.

기본적으로 Laravel은 terminate 메서드 호출 시 서비스 컨테이너에서 미들웨어의 새 인스턴스를 생성합니다. handleterminate가 동일한 인스턴스를 공유해야 한다면, 서비스 컨테이너에 싱글턴으로 등록하세요. 보통 AppServiceProviderregister 메서드에서 처리합니다:

use App\Http\Middleware\TerminatingMiddleware; /** * 애플리케이션 서비스를 등록합니다. */ public function register(): void { $this->app->singleton(TerminatingMiddleware::class); }

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 20일