미들웨어
업데이트됨번역일: 2026년 8월 10일
이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.
- 원문 수정
- 2026년 8월 10일
- 번역 갱신
- 2026년 8월 10일
미들웨어
소개
미들웨어는 애플리케이션에 들어오는 HTTP 요청을 검사하고 필터링하는 편리한 메커니즘입니다. 예를 들어, Laravel에는 사용자가 인증된 상태인지 확인하는 미들웨어가 내장되어 있습니다. 사용자가 인증되지 않은 경우 미들웨어는 로그인 화면으로 리디렉션하고, 인증된 경우에는 요청을 애플리케이션 내부로 통과시킵니다.
인증 외에도 다양한 목적의 미들웨어를 직접 작성할 수 있습니다. 예를 들어, 로깅 미들웨어는 모든 요청을 기록할 수 있습니다. Laravel에는 인증, CSRF 보호 등 여러 미들웨어가 기본 포함되어 있으며, 사용자가 직접 만든 미들웨어는 일반적으로 app/Http/Middleware 디렉터리에 위치합니다.
미들웨어 정의
새 미들웨어를 생성하려면 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이 일치하지 않으면 클라이언트에게 HTTP 리디렉션을 반환하고, 일치하면 $next($request)를 호출하여 요청을 애플리케이션 내부로 전달합니다.
미들웨어는 HTTP 요청이 애플리케이션에 도달하기 전에 통과해야 하는 일련의 "레이어"라고 생각하면 이해하기 쉽습니다. 각 레이어는 요청을 검사하거나 완전히 거부할 수 있습니다.
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): void {
$middleware->append(EnsureTokenIsValid::class);
})withMiddleware 클로저에 전달되는 $middleware 객체는 Illuminate\Foundation\Configuration\Middleware 인스턴스로, 애플리케이션의 미들웨어 스택을 관리합니다. append 메서드는 전역 미들웨어 목록의 끝에 추가하고, 목록의 앞에 추가하려면 prepend 메서드를 사용합니다.
전역 미들웨어 스택 직접 관리
전역 미들웨어 스택을 직접 구성하고 싶다면 use 메서드에 원하는 미들웨어 목록을 전달합니다:
->withMiddleware(function (Middleware $middleware): void {
$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 메서드를 사용합니다:
use App\Http\Middleware\First;
use App\Http\Middleware\Second;
->withMiddleware(function (Middleware $middleware): void {
$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은 web과 api라는 두 가지 미들웨어 그룹을 기본 제공합니다. 이 그룹들은 각각 routes/web.php와 routes/api.php 파일에 자동으로 적용됩니다:
web 미들웨어 그룹 |
|---|
Illuminate\Cookie\Middleware\EncryptCookies |
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse |
Illuminate\Session\Middleware\StartSession |
Illuminate\View\Middleware\ShareErrorsFromSession |
Illuminate\Foundation\Http\Middleware\PreventRequestForgery |
Illuminate\Routing\Middleware\SubstituteBindings |
api 미들웨어 그룹 |
|---|
Illuminate\Routing\Middleware\SubstituteBindings |
이 그룹에 미들웨어를 추가하거나 앞에 삽입하려면 bootstrap/app.php에서 web 및 api 메서드를 사용합니다:
use App\Http\Middleware\EnsureTokenIsValid;
use App\Http\Middleware\EnsureUserIsSubscribed;
->withMiddleware(function (Middleware $middleware): void {
$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,
]);기본 미들웨어 그룹 직접 관리
web과 api 미들웨어 그룹을 처음부터 직접 구성하고 싶다면 아래와 같이 그룹 전체를 재정의할 수 있습니다:
->withMiddleware(function (Middleware $middleware): void {
$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\PreventRequestForgery::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
web과 api 미들웨어 그룹은 bootstrap/app.php에 의해 각각 routes/web.php와 routes/api.php에 자동으로 적용됩니다.
미들웨어 별칭
클래스명이 긴 미들웨어에 짧은 별칭을 붙여 사용할 수 있습니다. bootstrap/app.php에서 alias 메서드로 별칭을 등록합니다:
use App\Http\Middleware\EnsureUserIsSubscribed;
->withMiddleware(function (Middleware $middleware): void {
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class
]);
})별칭을 등록한 후에는 라우트에 간단하게 사용할 수 있습니다:
Route::get('/profile', function () {
// ...
})->middleware('subscribed');편의를 위해 Laravel 내장 미들웨어 중 일부는 기본 별칭이 지정되어 있습니다. 예를 들어, auth 별칭은 Illuminate\Auth\Middleware\Authenticate 미들웨어를 가리킵니다. 기본 별칭 목록은 다음과 같습니다:
| 별칭 | 미들웨어 |
|---|---|
auth | Illuminate\Auth\Middleware\Authenticate |
auth.basic | Illuminate\Auth\Middleware\AuthenticateWithBasicAuth |
auth.session | Illuminate\Session\Middleware\AuthenticateSession |
cache.headers | Illuminate\Http\Middleware\SetCacheHeaders |
can | Illuminate\Auth\Middleware\Authorize |
guest | Illuminate\Auth\Middleware\RedirectIfAuthenticated |
password.confirm | Illuminate\Auth\Middleware\RequirePassword |
precognitive | Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests |
signed | Illuminate\Routing\Middleware\ValidateSignature |
subscribed | \Spark\Http\Middleware\VerifyBillableIsSubscribed |
throttle | Illuminate\Routing\Middleware\ThrottleRequests or Illuminate\Routing\Middleware\ThrottleRequestsWithRedis |
verified | Illuminate\Auth\Middleware\EnsureEmailIsVerified |
미들웨어 실행 순서 지정
드물지만, 라우트에 미들웨어가 할당된 순서와 무관하게 특정 실행 순서를 보장해야 할 때가 있습니다. 이런 경우 bootstrap/app.php에서 priority 메서드로 우선순위를 지정합니다:
->withMiddleware(function (Middleware $middleware): void {
$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\PreventRequestForgery::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,
]);
})기존 우선순위 목록을 유지하면서 특정 위치에 미들웨어를 삽입하려면 prependToPriorityList 또는 appendToPriorityList 메서드를 사용합니다. prependToPriorityList는 지정한 미들웨어 앞에, appendToPriorityList는 뒤에 삽입합니다:
->withMiddleware(function (Middleware $middleware): void {
$middleware->prependToPriorityList(
before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
prepend: \App\Http\Middleware\EnsureTokenIsValid::class,
);
$middleware->appendToPriorityList(
after: \Illuminate\Routing\Middleware\SubstituteBindings::class,
append: \App\Http\Middleware\EnsureUserIsSubscribed::class,
);
})before와 after 인자에는 미들웨어 클래스 배열을 전달할 수도 있습니다.
미들웨어 파라미터
미들웨어는 추가 파라미터를 받을 수 있습니다. 예를 들어, 특정 작업 전에 사용자가 지정한 "역할(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 메서드는 요청과 응답 객체를 모두 인자로 받습니다. 종료 가능한 미들웨어를 정의한 후에는 bootstrap/app.php에서 라우트 미들웨어 또는 전역 미들웨어로 등록해야 합니다.
terminate 메서드가 호출될 때 Laravel은 서비스 컨테이너에서 미들웨어의 새 인스턴스를 생성합니다. handle과 terminate가 동일한 인스턴스를 사용해야 한다면, AppServiceProvider의 register 메서드에서 컨테이너에 싱글턴으로 등록합니다:
use App\Http\Middleware\TerminatingMiddleware;
/**
* 애플리케이션 서비스를 등록합니다.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}