미들웨어
업데이트됨번역일: 2026년 10월 2일
이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.
- 원문 수정
- 2026년 10월 2일
- 번역 갱신
- 2026년 10월 2일
미들웨어
소개
미들웨어는 애플리케이션으로 들어오는 HTTP 요청을 검사하고 필터링할 수 있는 편리한 수단입니다. 예를 들어 Laravel에는 사용자가 인증되었는지 확인하는 미들웨어가 기본으로 포함되어 있습니다. 인증되지 않은 사용자라면 로그인 화면으로 리다이렉트시키고, 인증된 사용자라면 요청이 애플리케이션 내부로 계속 진행되도록 허용합니다.
인증 외에도 다양한 작업을 수행하는 미들웨어를 직접 작성할 수 있습니다. 예를 들어 들어오는 모든 요청을 기록하는 로깅 미들웨어를 만들 수도 있습니다. Laravel은 인증, CSRF 보호 등을 위한 여러 미들웨어를 기본 제공하지만, 사용자가 직접 정의하는 미들웨어는 보통 app/Http/Middleware 디렉터리에 위치합니다.
미들웨어 정의하기
새 미들웨어를 만들려면 make:middleware Artisan 명령어를 사용합니다:
php artisan make:middleware EnsureTokenIsValid이 명령어를 실행하면 app/Http/Middleware 디렉터리에 새로운 EnsureTokenIsValid 클래스가 생성됩니다. 이 미들웨어에서는 전달된 token 입력값이 지정된 값과 일치할 때만 라우트 접근을 허용하고, 그렇지 않으면 사용자를 /home URI로 리다이렉트합니다:
<?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
모든 미들웨어는 서비스 컨테이너를 통해 해석(resolve)되므로, 미들웨어의 생성자에서 필요한 의존성을 타입힌트로 지정해 주입받을 수 있습니다.
미들웨어와 응답
미들웨어는 요청이 애플리케이션으로 전달되기 전뿐만 아니라 이후에도 작업을 수행할 수 있습니다. 예를 들어 아래 미들웨어는 요청이 애플리케이션에서 처리되기 전에 어떤 작업을 수행합니다:
<?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 메서드를 사용하세요.
Laravel 기본 전역 미들웨어 직접 관리하기
Laravel의 전역 미들웨어 스택을 직접 수동으로 관리하고 싶다면, use 메서드에 Laravel의 기본 전역 미들웨어 목록을 그대로 전달한 뒤 필요에 맞게 조정하면 됩니다:
->withMiddleware(function (Middleware $middleware): void {
$middleware->use([
\Illuminate\Http\Middleware\ValidatePathEncoding::class,
\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);middleware 메서드에 미들웨어 이름 배열을 전달하면 하나의 라우트에 여러 미들웨어를 한꺼번에 할당할 수도 있습니다:
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 () {
// ...
});
});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에는 웹 라우트와 API 라우트에 흔히 적용하는 미들웨어를 모아둔 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 메서드를 사용하면 됩니다. 이 두 메서드는 appendToGroup 메서드를 더 간편하게 사용할 수 있도록 만들어진 대안입니다:
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,
]);
})Laravel 기본 미들웨어 그룹에 포함된 항목 중 하나를 자신만의 커스텀 미들웨어로 교체할 수도 있습니다:
use App\Http\Middleware\StartCustomSession;
use Illuminate\Session\Middleware\StartSession;
$middleware->web(replace: [
StartSession::class => StartCustomSession::class,
]);아예 특정 미들웨어를 완전히 제거할 수도 있습니다:
$middleware->web(remove: [
StartSession::class,
]);Laravel 기본 미들웨어 그룹 직접 관리하기
Laravel 기본 web, api 미들웨어 그룹에 포함된 모든 미들웨어를 직접 관리하고 싶다면, 그룹 전체를 다시 정의하면 됩니다. 아래 예시는 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
]);
})bootstrap/app.php 파일에서 미들웨어 별칭을 정의하고 나면, 라우트에 미들웨어를 할당할 때 이 별칭을 사용할 수 있습니다:
Route::get('/profile', function () {
// ...
})->middleware('subscribed');편의를 위해 Laravel에 내장된 일부 미들웨어는 기본적으로 별칭이 지정되어 있습니다. 예를 들어 auth는 Illuminate\Auth\Middleware\Authenticate 미들웨어의 별칭입니다. 아래는 Laravel이 기본으로 제공하는 미들웨어 별칭 목록입니다:
| 별칭 | 미들웨어 |
|---|---|
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 또는 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 App\Http\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)을 모두 인자로 받아야 합니다. 종료 가능한(terminable) 미들웨어를 정의했다면, 애플리케이션의 bootstrap/app.php 파일에서 라우트 미들웨어나 전역 미들웨어 목록에 추가해 주어야 합니다.
Laravel은 미들웨어의 terminate 메서드를 호출할 때 서비스 컨테이너에서 해당 미들웨어의 새로운 인스턴스를 다시 해석(resolve)합니다. 만약 handle 메서드와 terminate 메서드가 호출될 때 동일한 미들웨어 인스턴스를 사용하고 싶다면, 컨테이너의 singleton 메서드로 미들웨어를 등록하면 됩니다. 이 작업은 보통 AppServiceProvider의 register 메서드에서 수행합니다:
use App\Http\Middleware\TerminatingMiddleware;
/**
* 애플리케이션 서비스를 등록합니다.
*/
public function register(): void
{
$this->app->singleton(TerminatingMiddleware::class);
}