翻譯進度
45.45% 已翻譯
更新時間:
2024年6月30日 上午8:27:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

產生 URL

簡介

Laravel 提供了多種輔助函式,來協助你為你的專案產生 URL。對於在樣板或 API 的 Response 中建立連結、或是產生要重新導向到網站中另一個部分的 Redirect Response 時特別實用。

基礎

產生 URL

可使用 url 輔助函式來為你的網站產生任意 URL。產生的 URL 會自動使用網站目前收到 Request 的配置(HTTP 或 HTTPS) 與主機名稱:

1$post = App\Models\Post::find(1);
2 
3echo url("/posts/{$post->id}");
4 
5// http://example.com/posts/1
1$post = App\Models\Post::find(1);
2 
3echo url("/posts/{$post->id}");
4 
5// http://example.com/posts/1

Accessing the Current URL

若未提供路徑給 url 輔助函式,則會回傳 Illuminate\Routing\UrlGenerator 實體,使用該實體能讓我們存取有關目前 URL 的資訊:

1// Get the current URL without the query string...
2echo url()->current();
3 
4// Get the current URL including the query string...
5echo url()->full();
6 
7// Get the full URL for the previous request...
8echo url()->previous();
1// Get the current URL without the query string...
2echo url()->current();
3 
4// Get the current URL including the query string...
5echo url()->full();
6 
7// Get the full URL for the previous request...
8echo url()->previous();

這些方法也可以通過 URL Facade 來存取:

1use Illuminate\Support\Facades\URL;
2 
3echo URL::current();
1use Illuminate\Support\Facades\URL;
2 
3echo URL::current();

URLs for Named Routes

也可以使用 route 輔助函式來產生命名 Route的 URL。使用命名 Route 能讓我們不需要耦合到 Route 上實際定義的 URL,就能產生 URL。因此,即使 Route 的 URL 更改了,我們也不需要修改 route 函式的呼叫。舉例來說,假設我們的專案中有像這樣定義的 Route:

1Route::get('/post/{post}', function (Post $post) {
2 // ...
3})->name('post.show');
1Route::get('/post/{post}', function (Post $post) {
2 // ...
3})->name('post.show');

若要產生這個 Route 的 URL,可以像這樣使用 route 輔助函式:

1echo route('post.show', ['post' => 1]);
2 
3// http://example.com/post/1
1echo route('post.show', ['post' => 1]);
2 
3// http://example.com/post/1

當然,也可以使用 route 輔助函式來為有多個參數的 Route 產生 URL:

1Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) {
2 // ...
3})->name('comment.show');
4 
5echo route('comment.show', ['post' => 1, 'comment' => 3]);
6 
7// http://example.com/post/1/comment/3
1Route::get('/post/{post}/comment/{comment}', function (Post $post, Comment $comment) {
2 // ...
3})->name('comment.show');
4 
5echo route('comment.show', ['post' => 1, 'comment' => 3]);
6 
7// http://example.com/post/1/comment/3

若有陣列元素對應不上 Route 中定義的參數時,這些元素會被加到 URL 的查詢字串上:

1echo route('post.show', ['post' => 1, 'search' => 'rocket']);
2 
3// http://example.com/post/1?search=rocket
1echo route('post.show', ['post' => 1, 'search' => 'rocket']);
2 
3// http://example.com/post/1?search=rocket

Eloquent Model

我們常常會使用 Eloquent Model 的 Route 索引鍵 (通常是主索引鍵 - Primary Key) 來產生 URL。因此,我們也可以將 Eloquent Model 作為參數值傳入。route 輔助函式會自動取出 Model 的 Route 索引鍵:

1echo route('post.show', ['post' => $post]);
1echo route('post.show', ['post' => $post]);

簽名 URL

Laravel 能讓我們輕鬆地為命名 Route 建立「簽名的 (Signed)」URL。這種 URL 的查詢字串中有個「簽名」雜湊,能讓 Laravel 驗證這個 URL 建立後是否有被修改。簽名的 URL 特別適用於一些可公開存取但又需要保護網址不被任意修改的 Route。

舉例來說,我們可以使用簽名 URL 來實作公開「解除訂閱」的連結,這個連結會寄給使用者。若要為命名路由建立簽名 URL,可使用 URL Facade 的 signedRoute 方法:

1use Illuminate\Support\Facades\URL;
2 
3return URL::signedRoute('unsubscribe', ['user' => 1]);
1use Illuminate\Support\Facades\URL;
2 
3return URL::signedRoute('unsubscribe', ['user' => 1]);

可以提供 absolute 引數給 signedRoute 方法來在 URL 簽名 Hash 中排除網域:

1return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
1return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);

若想產生在指定時間後會過期的臨時簽名 Route URL,可以使用 temporarySignedRoute 方法。Laravel 在驗證臨時簽名 Route URL 時,也會確保被編碼進簽名 URL 中的過期時間時戳尚未到期:

1use Illuminate\Support\Facades\URL;
2 
3return URL::temporarySignedRoute(
4 'unsubscribe', now()->addMinutes(30), ['user' => 1]
5);
1use Illuminate\Support\Facades\URL;
2 
3return URL::temporarySignedRoute(
4 'unsubscribe', now()->addMinutes(30), ['user' => 1]
5);

驗證簽名 Route 的 Request

若要驗證連入 Request 是否有正確的簽名,可在連入的 Illuminate\Http\Request 實體上呼叫 hasValidSignature 方法:

1use Illuminate\Http\Request;
2 
3Route::get('/unsubscribe/{user}', function (Request $request) {
4 if (! $request->hasValidSignature()) {
5 abort(401);
6 }
7 
8 // ...
9})->name('unsubscribe');
1use Illuminate\Http\Request;
2 
3Route::get('/unsubscribe/{user}', function (Request $request) {
4 if (! $request->hasValidSignature()) {
5 abort(401);
6 }
7 
8 // ...
9})->name('unsubscribe');

有時候,我們可能要讓程式的前端將資料附加到簽名 URL 上,例如在用戶端上做分頁時。因此,我們可以使用 hasValidSignatureWhileIgnoring 來指定哪些查詢參數在驗證簽名 URL 要被忽略不驗證。但請記得,忽略一個參數就能讓任何人都能修改這個參數:

1if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
2 abort(401);
3}
1if (! $request->hasValidSignatureWhileIgnoring(['page', 'order'])) {
2 abort(401);
3}

Instead of validating signed URLs using the incoming request instance, you may assign the signed (Illuminate\Routing\Middleware\ValidateSignature) middleware to the route. If the incoming request does not have a valid signature, the middleware will automatically return a 403 HTTP response:

1Route::post('/unsubscribe/{user}', function (Request $request) {
2 // ...
3})->name('unsubscribe')->middleware('signed');
1Route::post('/unsubscribe/{user}', function (Request $request) {
2 // ...
3})->name('unsubscribe')->middleware('signed');

若在簽名的 URL 中,URL Hash 不包含網域,則需要在 Middleware 中包含 relative 引數:

1Route::post('/unsubscribe/{user}', function (Request $request) {
2 // ...
3})->name('unsubscribe')->middleware('signed:relative');
1Route::post('/unsubscribe/{user}', function (Request $request) {
2 // ...
3})->name('unsubscribe')->middleware('signed:relative');

Responding to Invalid Signed Routes

When someone visits a signed URL that has expired, they will receive a generic error page for the 403 HTTP status code. However, you can customize this behavior by defining a custom "render" closure for the InvalidSignatureException exception in your application's bootstrap/app.php file:

1use Illuminate\Routing\Exceptions\InvalidSignatureException;
2 
3->withExceptions(function (Exceptions $exceptions) {
4 $exceptions->render(function (InvalidSignatureException $e) {
5 return response()->view('error.link-expired', [], 403);
6 });
7})
1use Illuminate\Routing\Exceptions\InvalidSignatureException;
2 
3->withExceptions(function (Exceptions $exceptions) {
4 $exceptions->render(function (InvalidSignatureException $e) {
5 return response()->view('error.link-expired', [], 403);
6 });
7})

URLs for Controller Actions

action 方法可為給定的 Controller 動作產生 URL:

1use App\Http\Controllers\HomeController;
2 
3$url = action([HomeController::class, 'index']);
1use App\Http\Controllers\HomeController;
2 
3$url = action([HomeController::class, 'index']);

若該 Controller 方法接受 Route 參數,則可將 Route 參數的關聯式陣列作為第二個引數傳給給函式:

1$url = action([UserController::class, 'profile'], ['id' => 1]);
1$url = action([UserController::class, 'profile'], ['id' => 1]);

預設值

在某個專案中,我們可能會想為特定的 URL 參數設定 Request 層級的預設值。舉例來說,假設我們的 Route 中很多都定義了 {locale} 參數:

1Route::get('/{locale}/posts', function () {
2 // ...
3})->name('post.index');
1Route::get('/{locale}/posts', function () {
2 // ...
3})->name('post.index');

若每次呼叫 route 輔助函式都要傳入 locale 的話會很麻煩。因此。我們可以使用 URL::defaults 方法來為這個參數定義目前 Request 中要套用的預設值。建議在某個 Route Middleware 中呼叫這個方法,這樣我們才能存取目前的 Request:

1<?php
2 
3namespace App\Http\Middleware;
4 
5use Closure;
6use Illuminate\Http\Request;
7use Illuminate\Support\Facades\URL;
8use Symfony\Component\HttpFoundation\Response;
9 
10class SetDefaultLocaleForUrls
11{
12 /**
13 * Handle an incoming request.
14 *
15 * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
16 */
17 public function handle(Request $request, Closure $next): Response
18 {
19 URL::defaults(['locale' => $request->user()->locale]);
20 
21 return $next($request);
22 }
23}
1<?php
2 
3namespace App\Http\Middleware;
4 
5use Closure;
6use Illuminate\Http\Request;
7use Illuminate\Support\Facades\URL;
8use Symfony\Component\HttpFoundation\Response;
9 
10class SetDefaultLocaleForUrls
11{
12 /**
13 * Handle an incoming request.
14 *
15 * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
16 */
17 public function handle(Request $request, Closure $next): Response
18 {
19 URL::defaults(['locale' => $request->user()->locale]);
20 
21 return $next($request);
22 }
23}

locale 參數設定好預設值後,使用 route 輔助函式產生 URL 時就不需要再傳入這個值了:

URL Defaults and Middleware Priority

Setting URL default values can interfere with Laravel's handling of implicit model bindings. Therefore, you should prioritize your middleware that set URL defaults to be executed before Laravel's own SubstituteBindings middleware. You can accomplish this using the priority middleware method in your application's bootstrap/app.php file:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->priority([
3 \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
4 \Illuminate\Cookie\Middleware\EncryptCookies::class,
5 \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
6 \Illuminate\Session\Middleware\StartSession::class,
7 \Illuminate\View\Middleware\ShareErrorsFromSession::class,
8 \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
9 \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
10 \Illuminate\Routing\Middleware\ThrottleRequests::class,
11 \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
12 \Illuminate\Session\Middleware\AuthenticateSession::class,
13 \App\Http\Middleware\SetDefaultLocaleForUrls::class,
14 \Illuminate\Routing\Middleware\SubstituteBindings::class,
15 \Illuminate\Auth\Middleware\Authorize::class,
16 ]);
17})
1->withMiddleware(function (Middleware $middleware) {
2 $middleware->priority([
3 \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
4 \Illuminate\Cookie\Middleware\EncryptCookies::class,
5 \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
6 \Illuminate\Session\Middleware\StartSession::class,
7 \Illuminate\View\Middleware\ShareErrorsFromSession::class,
8 \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
9 \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
10 \Illuminate\Routing\Middleware\ThrottleRequests::class,
11 \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
12 \Illuminate\Session\Middleware\AuthenticateSession::class,
13 \App\Http\Middleware\SetDefaultLocaleForUrls::class,
14 \Illuminate\Routing\Middleware\SubstituteBindings::class,
15 \Illuminate\Auth\Middleware\Authorize::class,
16 ]);
17})
翻譯進度
45.45% 已翻譯
更新時間:
2024年6月30日 上午8:27:00 [世界標準時間]
翻譯人員:
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.