URL 생성
번역일: 2026년 6월 20일
URL 생성
소개
Laravel은 애플리케이션 내에서 URL을 손쉽게 생성할 수 있도록 다양한 헬퍼를 제공합니다. 이 헬퍼들은 주로 Blade 템플릿이나 API 응답에서 링크를 만들거나, 다른 페이지로의 리다이렉트 응답을 구성할 때 유용하게 활용됩니다.
기본 사용법
URL 생성하기
url 헬퍼를 사용하면 애플리케이션의 임의 URL을 생성할 수 있습니다. 생성된 URL은 현재 요청의 스킴(HTTP 또는 HTTPS)과 호스트를 자동으로 반영합니다.
$post = App\Models\Post::find(1);
echo url("/posts/{$post->id}");
// http://example.com/posts/1현재 URL 조회하기
url 헬퍼에 경로를 전달하지 않으면 Illuminate\Routing\UrlGenerator 인스턴스가 반환됩니다. 이를 통해 현재 URL에 대한 다양한 정보를 조회할 수 있습니다.
// 쿼리 스트링 없이 현재 URL 반환
echo url()->current();
// 쿼리 스트링을 포함한 현재 URL 반환
echo url()->full();
// 이전 요청의 전체 URL 반환
echo url()->previous();이 메서드들은 URL 파사드를 통해서도 동일하게 사용할 수 있습니다.
use Illuminate\Support\Facades\URL;
echo URL::current();이름 있는 라우트 URL
route 헬퍼를 사용하면 이름 있는 라우트의 URL을 생성할 수 있습니다. 이름 있는 라우트를 활용하면 실제 URL 경로에 의존하지 않고 URL을 생성할 수 있으므로, 나중에 라우트의 경로가 변경되더라도 route 함수를 호출하는 코드를 수정할 필요가 없습니다.
예를 들어, 다음과 같이 라우트를 정의했다고 가정해 보겠습니다.
Route::get('/post/{post}', function (Post $post) {
// ...
})->name('post.show');이 라우트의 URL은 다음과 같이 생성합니다.
echo route('post.show', ['post' => 1]);
// http://example.com/post/1파라미터가 여러 개인 라우트도 동일하게 처리합니다.
Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) {
// ...
})->name('comment.show');
echo route('comment.show', ['post' => 1, 'comment' => 3]);
// http://example.com/post/1/comment/3라우트 정의에 없는 파라미터를 추가로 전달하면, 해당 값은 자동으로 쿼리 스트링으로 붙습니다.
echo route('post.show', ['post' => 1, 'search' => 'rocket']);
// http://example.com/post/1?search=rocketEloquent 모델 전달
URL 생성 시 라우트 키(보통 기본 키)가 필요한 경우가 많습니다. Eloquent 모델 인스턴스를 파라미터로 직접 전달하면, route 헬퍼가 모델의 라우트 키를 자동으로 추출하여 사용합니다.
echo route('post.show', ['post' => $post]);서명된 URL
Laravel은 이름 있는 라우트에 대해 "서명된(signed) URL"을 쉽게 생성할 수 있는 기능을 제공합니다. 서명된 URL은 쿼리 스트링에 해시 서명값(signature)이 포함되어, URL이 생성된 이후 변조되지 않았음을 검증할 수 있습니다. 공개적으로 접근 가능하지만 URL 위·변조로부터 보호가 필요한 라우트에 특히 유용합니다.
예를 들어, 이메일로 발송하는 "수신 거부(unsubscribe)" 링크처럼 외부에 노출되는 URL에 활용할 수 있습니다. 서명된 URL은 URL 파사드의 signedRoute 메서드로 생성합니다.
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);서명 해시에서 도메인을 제외하려면 absolute 인수를 false로 지정합니다.
return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);일정 시간 후 만료되는 임시 서명 URL이 필요하다면 temporarySignedRoute 메서드를 사용합니다. Laravel은 이 URL을 검증할 때 인코딩된 만료 시각이 지났는지 함께 확인합니다.
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);서명된 라우트 요청 검증
들어오는 요청의 서명이 유효한지 확인하려면, Illuminate\Http\Request 인스턴스의 hasValidSignature 메서드를 호출합니다.
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');클라이언트 측 페이지네이션처럼 프론트엔드에서 서명된 URL에 쿼리 파라미터를 동적으로 추가해야 하는 경우가 있습니다. 이럴 때는 hasValidSignatureWhileIgnoring 메서드로 검증 시 무시할 파라미터를 지정할 수 있습니다.
NOTE
무시 대상으로 지정된 파라미터는 누구나 임의로 변경할 수 있으므로, 보안상 민감한 값은 무시 목록에 포함하지 않도록 주의하세요.
if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
abort(401);
}요청 인스턴스로 직접 검증하는 대신, Illuminate\Routing\Middleware\ValidateSignature 미들웨어를 라우트에 지정할 수도 있습니다. 아직 등록되지 않은 경우, HTTP 커널의 $middlewareAliases 배열에 별칭을 추가합니다.
/**
* 애플리케이션 미들웨어 별칭
*
* 별칭을 사용하면 라우트 및 그룹에 미들웨어를 간편하게 지정할 수 있습니다.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
];미들웨어를 등록한 후 라우트에 적용하면, 유효하지 않은 서명의 요청은 자동으로 403 HTTP 응답을 반환합니다.
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');서명된 URL에 도메인이 포함되지 않는 경우(즉, absolute: false로 생성한 경우)에는 미들웨어에 relative 인수를 전달해야 합니다.
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed:relative');유효하지 않은 서명 URL 처리
만료된 서명 URL에 접근하면 기본적으로 403 상태 코드의 일반 오류 페이지가 표시됩니다. 예외 핸들러에서 InvalidSignatureException에 대한 커스텀 렌더링 클로저를 정의하면 이 동작을 원하는 대로 변경할 수 있습니다.
use Illuminate\Routing\Exceptions\InvalidSignatureException;
/**
* 애플리케이션의 예외 처리 콜백을 등록합니다.
*/
public function register(): void
{
$this->renderable(function (InvalidSignatureException $e) {
return response()->view('error.link-expired', [], 403);
});
}컨트롤러 액션 URL
action 함수를 사용하면 특정 컨트롤러 액션에 대한 URL을 생성할 수 있습니다.
use App\Http\Controllers\HomeController;
$url = action([HomeController::class, 'index']);컨트롤러 메서드가 라우트 파라미터를 받는 경우, 두 번째 인수로 파라미터 배열을 전달합니다.
$url = action([UserController::class, 'profile'], ['id' => 1]);기본값 설정
일부 애플리케이션에서는 특정 URL 파라미터에 요청 전반에 걸친 기본값을 지정해야 할 수 있습니다. 예를 들어, 다음과 같이 많은 라우트에 {locale} 파라미터가 정의되어 있다고 가정해 보겠습니다.
Route::get('/{locale}/posts', function () {
// ...
})->name('post.index');route 헬퍼를 호출할 때마다 locale을 매번 전달하는 것은 번거롭습니다. URL::defaults 메서드를 사용하면 현재 요청 동안 항상 적용될 파라미터 기본값을 지정할 수 있습니다. 현재 요청 정보에 접근해야 하므로, 이 메서드는 라우트 미들웨어 내에서 호출하는 것이 일반적입니다.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\URL;
use Symfony\Component\HttpFoundation\Response;
class SetDefaultLocaleForUrls
{
/**
* 들어오는 요청을 처리합니다.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
URL::defaults(['locale' => $request->user()->locale]);
return $next($request);
}
}locale 파라미터의 기본값이 설정되면, 이후 route 헬퍼로 URL을 생성할 때 해당 값을 별도로 전달하지 않아도 됩니다.
URL 기본값과 미들웨어 우선순위
URL 기본값을 설정하면 Laravel의 암묵적 모델 바인딩(implicit model binding) 처리와 충돌할 수 있습니다. 따라서 URL 기본값을 설정하는 미들웨어는 Laravel 내장 SubstituteBindings 미들웨어보다 먼저 실행되도록 미들웨어 우선순위를 지정해야 합니다.
HTTP 커널의 $middlewarePriority 속성에서 순서를 조정하면 됩니다. 이 속성은 기본적으로 Illuminate\Foundation\Http\Kernel 베이스 클래스에 정의되어 있으므로, 해당 정의를 복사하여 애플리케이션의 HTTP 커널에서 재정의할 수 있습니다.
/**
* 우선순위가 지정된 미들웨어 목록
*
* 비전역 미들웨어가 항상 지정된 순서로 실행되도록 강제합니다.
*
* @var array
*/
protected $middlewarePriority = [
// ...
\App\Http\Middleware\SetDefaultLocaleForUrls::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// ...
];