라우팅
번역일: 2026년 6월 21일
라우팅
- 기본 라우팅
- 라우트 파라미터
- 이름이 있는 라우트
- 라우트 그룹
- 라우트 모델 바인딩
- 폴백 라우트
- 요청 빈도 제한
- 폼 메서드 스푸핑
- 현재 라우트 접근
- 교차 출처 리소스 공유 (CORS)
- 라우트 캐싱
기본 라우팅
Laravel에서 라우트를 정의하는 가장 기본적인 방법은 URI와 클로저를 함께 등록하는 것입니다. 별도의 복잡한 설정 파일 없이도 간결하고 직관적으로 라우트와 동작을 정의할 수 있습니다.
use Illuminate\Support\Facades\Route;
Route::get('/greeting', function () {
return '안녕하세요!';
});기본 라우트 파일
애플리케이션의 모든 라우트는 routes 디렉터리 안의 파일에서 정의합니다. 이 파일들은 bootstrap/app.php에 지정된 설정에 따라 Laravel이 자동으로 불러옵니다.
routes/web.php 파일은 웹 인터페이스용 라우트를 정의하는 곳입니다. 이 파일의 라우트는 web 미들웨어 그룹에 속하며, 세션 상태 유지와 CSRF 보호 기능이 자동으로 적용됩니다.
대부분의 경우 routes/web.php에서 라우트 정의를 시작합니다. 예를 들어 아래 라우트는 브라우저에서 http://example.com/user에 접속하면 동작합니다.
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'index']);API 라우트
상태를 유지하지 않는 API도 제공해야 한다면, install:api Artisan 명령어로 API 라우팅을 활성화할 수 있습니다.
php artisan install:api이 명령어는 Laravel Sanctum을 설치합니다. Sanctum은 서드파티 API 클라이언트, SPA, 모바일 앱 인증에 활용할 수 있는 API 토큰 인증 기능을 제공합니다. 또한 routes/api.php 파일이 새로 생성됩니다.
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');routes/api.php의 라우트는 상태를 유지하지 않으며 api 미들웨어 그룹에 자동으로 속합니다. 또한 /api URI 접두사가 자동으로 붙으므로 파일 내 각 라우트에 일일이 명시할 필요가 없습니다. 접두사를 변경하려면 bootstrap/app.php를 수정하세요.
->withRouting(
api: __DIR__.'/../routes/api.php',
apiPrefix: 'api/admin',
// ...
)사용 가능한 HTTP 메서드
라우터는 모든 HTTP 메서드에 대응하는 라우트를 등록할 수 있습니다.
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);여러 HTTP 메서드를 동시에 처리해야 한다면 match를, 모든 메서드를 처리하려면 any를 사용하세요.
Route::match(['get', 'post'], '/', function () {
// ...
});
Route::any('/', function () {
// ...
});NOTE
같은 URI를 가진 라우트를 여러 개 정의할 때는 get, post, put, patch, delete, options 메서드로 등록한 라우트를 any, match, redirect 메서드로 등록한 라우트보다 먼저 정의해야 합니다. 그래야 요청이 올바른 라우트와 매칭됩니다.
의존성 주입
라우트 콜백의 인자에 타입 힌트를 선언하면, Laravel 서비스 컨테이너가 해당 의존성을 자동으로 주입해줍니다. 예를 들어 Illuminate\Http\Request를 타입 힌트로 선언하면 현재 HTTP 요청 객체가 자동으로 주입됩니다.
use Illuminate\Http\Request;
Route::get('/users', function (Request $request) {
// ...
});CSRF 보호
web 라우트 파일에 정의된 POST, PUT, PATCH, DELETE 라우트를 대상으로 하는 HTML 폼에는 반드시 CSRF 토큰 필드를 포함해야 합니다. 그렇지 않으면 요청이 거부됩니다. CSRF 보호에 대한 자세한 내용은 CSRF 문서를 참고하세요.
<form method="POST" action="/profile">
@csrf
...
</form>리다이렉트 라우트
다른 URI로 리다이렉트하는 라우트는 Route::redirect 메서드를 사용하면 편리합니다. 별도의 컨트롤러나 전체 라우트를 정의하지 않고도 간단하게 리다이렉트를 구현할 수 있습니다.
Route::redirect('/here', '/there');기본적으로 302 상태 코드를 반환합니다. 세 번째 인자로 원하는 상태 코드를 지정할 수 있습니다.
Route::redirect('/here', '/there', 301);301 상태 코드로 영구 리다이렉트하려면 Route::permanentRedirect를 사용하세요.
Route::permanentRedirect('/here', '/there');WARNING
리다이렉트 라우트에서 라우트 파라미터를 사용할 때, destination과 status는 Laravel이 예약한 파라미터 이름이므로 사용할 수 없습니다.
뷰 라우트
라우트에서 단순히 뷰만 반환하면 된다면 Route::view 메서드를 사용하세요. 첫 번째 인자에 URI, 두 번째 인자에 뷰 이름을 지정합니다. 세 번째 인자로 뷰에 전달할 데이터 배열을 선택적으로 지정할 수도 있습니다.
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => '홍길동']);WARNING
뷰 라우트에서 라우트 파라미터를 사용할 때, view, data, status, headers는 Laravel이 예약한 파라미터 이름이므로 사용할 수 없습니다.
라우트 목록 확인
route:list Artisan 명령어를 사용하면 애플리케이션에 등록된 모든 라우트를 한눈에 확인할 수 있습니다.
php artisan route:list기본 출력에는 각 라우트에 적용된 미들웨어가 표시되지 않습니다. -v 옵션을 추가하면 미들웨어와 미들웨어 그룹 이름이 함께 표시됩니다.
php artisan route:list -v# 미들웨어 그룹 상세 표시php artisan route:list -vv특정 URI로 시작하는 라우트만 표시하려면 --path 옵션을 사용하세요.
php artisan route:list --path=api서드파티 패키지에서 등록된 라우트를 제외하고 표시하려면 --except-vendor 옵션을 사용하세요.
php artisan route:list --except-vendor반대로 서드파티 패키지에서 등록된 라우트만 표시하려면 --only-vendor 옵션을 사용하세요.
php artisan route:list --only-vendor라우팅 커스터마이징
기본적으로 애플리케이션의 라우트는 bootstrap/app.php에서 설정하고 불러옵니다.
<?php
use Illuminate\Foundation\Application;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)->create();필요에 따라 별도의 라우트 파일을 추가하고 싶다면, withRouting 메서드에 then 클로저를 전달하세요. 이 클로저 안에서 추가 라우트를 자유롭게 등록할 수 있습니다.
use Illuminate\Support\Facades\Route;
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
then: function () {
Route::middleware('api')
->prefix('webhooks')
->name('webhooks.')
->group(base_path('routes/webhooks.php'));
},
)라우트 등록 전체를 직접 제어하고 싶다면 using 클로저를 전달하세요. 이 경우 프레임워크는 HTTP 라우트를 자동으로 등록하지 않으며, 모든 라우트를 직접 등록해야 합니다.
use Illuminate\Support\Facades\Route;
->withRouting(
commands: __DIR__.'/../routes/console.php',
using: function () {
Route::middleware('api')
->prefix('api')
->group(base_path('routes/api.php'));
Route::middleware('web')
->group(base_path('routes/web.php'));
},
)라우트 파라미터
필수 파라미터
URI의 일부를 동적으로 받아야 할 때 라우트 파라미터를 사용합니다. 예를 들어 URL에서 사용자 ID를 추출하려면 다음과 같이 정의합니다.
Route::get('/user/{id}', function (string $id) {
return '사용자 ID: ' . $id;
});파라미터는 여러 개 정의할 수 있습니다.
Route::get('/posts/{post}/comments/{comment}', function (string $postId, string $commentId) {
// ...
});라우트 파라미터는 {}로 감싸며, 영문자와 밑줄(_)로 구성할 수 있습니다. 파라미터는 정의된 순서대로 콜백 인자에 주입되므로, 콜백 인자의 변수명은 파라미터 이름과 달라도 됩니다.
파라미터와 의존성 주입
서비스 컨테이너에서 자동으로 주입받아야 하는 의존성이 있다면, 라우트 파라미터보다 앞에 선언하세요.
use Illuminate\Http\Request;
Route::get('/user/{id}', function (Request $request, string $id) {
return '사용자 ID: ' . $id;
});선택적 파라미터
URI에 항상 존재하지 않을 수 있는 파라미터는 파라미터 이름 뒤에 ?를 붙이고, 대응하는 변수에 기본값을 설정하세요.
Route::get('/user/{name?}', function (?string $name = null) {
return $name;
});
Route::get('/user/{name?}', function (?string $name = '홍길동') {
return $name;
});정규식 제약 조건
where 메서드를 사용하면 라우트 파라미터 형식을 정규식으로 제한할 수 있습니다.
Route::get('/user/{name}', function (string $name) {
// ...
})->where('name', '[A-Za-z]+');
Route::get('/user/{id}', function (string $id) {
// ...
})->where('id', '[0-9]+');
Route::get('/user/{id}/{name}', function (string $id, string $name) {
// ...
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);자주 사용하는 패턴은 전용 헬퍼 메서드로 간편하게 적용할 수 있습니다.
Route::get('/user/{id}/{name}', function (string $id, string $name) {
// ...
})->whereNumber('id')->whereAlpha('name');
Route::get('/user/{name}', function (string $name) {
// ...
})->whereAlphaNumeric('name');
Route::get('/user/{id}', function (string $id) {
// ...
})->whereUuid('id');
Route::get('/user/{id}', function (string $id) {
// ...
})->whereUlid('id');
Route::get('/category/{category}', function (string $category) {
// ...
})->whereIn('category', ['movie', 'song', 'painting']);
Route::get('/category/{category}', function (string $category) {
// ...
})->whereIn('category', CategoryEnum::cases());요청이 라우트 파라미터 제약 조건에 맞지 않으면 404 HTTP 응답이 반환됩니다.
전역 제약 조건
특정 파라미터 이름에 항상 동일한 정규식을 적용하려면 App\Providers\AppServiceProvider의 boot 메서드에서 Route::pattern을 사용하세요.
use Illuminate\Support\Facades\Route;
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Route::pattern('id', '[0-9]+');
}한 번 패턴을 등록하면 해당 파라미터 이름을 사용하는 모든 라우트에 자동으로 적용됩니다.
Route::get('/user/{id}', function (string $id) {
// {id}가 숫자인 경우에만 실행됩니다.
});슬래시(/) 문자 허용
Laravel의 라우팅 컴포넌트는 /를 제외한 모든 문자를 파라미터 값으로 허용합니다. 파라미터 값에 /를 포함시키려면 where 조건에서 명시적으로 허용해야 합니다.
Route::get('/search/{search}', function (string $search) {
return $search;
})->where('search', '.*');WARNING
슬래시를 포함한 파라미터는 라우트의 마지막 세그먼트에서만 지원됩니다.
이름이 있는 라우트
라우트에 이름을 지정하면 URL 생성이나 리다이렉트 시 라우트 이름을 활용할 수 있어 편리합니다. 라우트 정의에 name 메서드를 체이닝하여 이름을 지정합니다.
Route::get('/user/profile', function () {
// ...
})->name('profile');컨트롤러 액션에도 이름을 지정할 수 있습니다.
Route::get(
'/user/profile',
[UserProfileController::class, 'show']
)->name('profile');WARNING
라우트 이름은 애플리케이션 전체에서 고유해야 합니다.
이름이 있는 라우트의 URL 생성
라우트에 이름을 지정하면 route 헬퍼 함수나 redirect 헬퍼 함수에서 라우트 이름으로 URL을 생성하거나 리다이렉트할 수 있습니다.
// URL 생성
$url = route('profile');
// 리다이렉트
return redirect()->route('profile');
return to_route('profile');파라미터가 있는 라우트라면 두 번째 인자로 파라미터 값을 전달하세요. 파라미터는 URL의 올바른 위치에 자동으로 삽입됩니다.
Route::get('/user/{id}/profile', function (string $id) {
// ...
})->name('profile');
$url = route('profile', ['id' => 1]);배열에 라우트 파라미터로 정의되지 않은 추가 키-값 쌍을 전달하면 쿼리 스트링으로 자동 추가됩니다.
Route::get('/user/{id}/profile', function (string $id) {
// ...
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// /user/1/profile?photos=yesNOTE
현재 로케일처럼 요청 전반에 걸쳐 URL 파라미터 기본값을 지정하고 싶다면 URL::defaults 메서드를 사용하세요.
현재 라우트 이름 확인
현재 요청이 특정 이름의 라우트로 처리되고 있는지 확인하려면 Route 인스턴스의 named 메서드를 사용하세요. 미들웨어 내에서 활용하는 예시입니다.
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->route()->named('profile')) {
// ...
}
return $next($request);
}라우트 그룹
라우트 그룹을 사용하면 미들웨어 같은 공통 속성을 여러 라우트에 반복 지정하지 않고 한 번에 적용할 수 있습니다.
중첩된 그룹은 상위 그룹의 속성을 지능적으로 병합합니다. 미들웨어와 where 조건은 합쳐지고, 이름과 접두사는 이어 붙여집니다.
미들웨어
그룹 내 모든 라우트에 미들웨어를 적용하려면 그룹 정의 전에 middleware 메서드를 사용하세요. 미들웨어는 배열에 나열된 순서대로 실행됩니다.
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// first, second 미들웨어가 적용됩니다.
});
Route::get('/user/profile', function () {
// first, second 미들웨어가 적용됩니다.
});
});컨트롤러
그룹 내 모든 라우트가 동일한 컨트롤러를 사용한다면, controller 메서드로 공통 컨트롤러를 지정할 수 있습니다. 각 라우트에는 컨트롤러 메서드 이름만 지정하면 됩니다.
use App\Http\Controllers\OrderController;
Route::controller(OrderController::class)->group(function () {
Route::get('/orders/{id}', 'show');
Route::post('/orders', 'store');
});서브도메인 라우팅
라우트 그룹을 사용하여 서브도메인 라우팅을 처리할 수 있습니다. 서브도메인에도 URI 파라미터처럼 라우트 파라미터를 지정할 수 있으며, 이를 라우트나 컨트롤러에서 활용할 수 있습니다. domain 메서드로 서브도메인을 지정하세요.
Route::domain('{account}.example.com')->group(function () {
Route::get('/user/{id}', function (string $account, string $id) {
// ...
});
});WARNING
서브도메인 라우트가 정상적으로 동작하려면 루트 도메인 라우트보다 먼저 등록해야 합니다. 그렇지 않으면 동일한 URI 경로를 가진 루트 도메인 라우트가 서브도메인 라우트를 덮어쓸 수 있습니다.
라우트 접두사
prefix 메서드를 사용하면 그룹 내 모든 라우트 URI에 공통 접두사를 붙일 수 있습니다. 예를 들어 관리자용 라우트에 admin 접두사를 적용하는 예시입니다.
Route::prefix('admin')->group(function () {
Route::get('/users', function () {
// "/admin/users" URL에 매칭됩니다.
});
});라우트 이름 접두사
name 메서드를 사용하면 그룹 내 모든 라우트 이름에 공통 접두사를 붙일 수 있습니다. 접두사 문자열은 그대로 이어 붙여지므로, 끝에 .을 붙이는 것을 잊지 마세요.
Route::name('admin.')->group(function () {
Route::get('/users', function () {
// 라우트 이름: "admin.users"
})->name('users');
});라우트 모델 바인딩
라우트나 컨트롤러 액션에서 모델 ID를 받아 데이터베이스를 조회하는 패턴은 매우 일반적입니다. 라우트 모델 바인딩을 사용하면 이 과정을 자동화하여, ID 대신 해당 모델 인스턴스를 라우트에 직접 주입받을 수 있습니다.
암묵적 바인딩
라우트나 컨트롤러 액션에서 타입 힌트로 선언한 Eloquent 모델의 변수명이 라우트 세그먼트 이름과 일치하면, Laravel이 자동으로 해당 모델 인스턴스를 조회하여 주입합니다.
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
});$user 변수가 App\Models\User 모델로 타입 힌트되어 있고 변수명이 {user} 세그먼트와 일치하므로, Laravel은 URI의 값에 해당하는 ID를 가진 User 인스턴스를 자동으로 조회합니다. 일치하는 모델이 없으면 404 응답이