【Laravel實戰】Laravel網址生成全攻略
Laravel 提供了幾個幫助函式來為應用生成 URL。主要用於在模板和 API 回應中生成 URL 或者在應用的其它部分生成轉址回應
基礎
生成 URLs
幫助函式 url() 可以用於應用的任何一個 URL。生成的 URL 將自動使用當前請求中的協定 (HTTP or HTTPS) 和網域:
$post = App\Models\Post::find(1);
echo url("/posts/{$post->id}");
// http://example.com/posts/1
取得當前 URL
如果沒有為幫助函式 url() 提供路徑,則會回傳一個 Illuminate\Routing\UrlGenerator 實例,來允許你取得有關當前 URL 的資料:
// Get the current URL without the query string...
echo url()->current();
// Get the current URL including the query string...
echo url()->full();
// Get the full URL for the previous request...
echo url()->previous();
上面的這些方法都可以通過 URL Facade 來訪問:
use Illuminate\Support\Facades\URL;
echo URL::current();
命名路由的 URLs
幫助函式 route() 可以用於為指定路由生成 URL。命名路由生成的 URL 不與路由上定義的 URL 相耦合。因此就算路由的 URL 有任何改變,都不需要對 route() 呼叫進行任何更改。例如假設你的應用包含以下路由:
Route::get('/post/{post}', function () {
//
})->name('post.show');
要生成此路由的 URL ,可以像這樣使用幫助函式 route() :
echo route('post.show', ['post' => 1]);
// http://example.com/post/1
當然, route() 幫助函式也能傳入多個參數來生成 URLs
Route::get('/post/{post}/comment/{comment}', function () {
//
})->name('comment.show');
echo route('comment.show', ['post' => 1, 'comment' => 3]);
// http://example.com/post/1/comment/3
任何陣列的元素的鍵值如有不符合路由參數的部分將自動轉為 URL 的查詢字串
echo route('post.show', ['post' => 1, 'search' => 'rocket']);
// http://example.com/post/1?search=rocket
Eloquent 模型
你將很常利用 Eloquent 模型的主鍵來生成 URLs。因此,你何不直接傳入 Eloquent 模型作為參數值, route() 將會自動的取用模型的主鍵
echo route('post.show', ['post' => $post]);
簽名 URLs
Laravel 允許你輕鬆地為命名路徑創建「簽名」URL,這些 URL 在查詢字串後附加了「簽名」Hash,允許 Laravel 驗證 URL 自創建以來未被修改過。簽名 URL 對於可公開訪問但需要一層防止 URL 操作的路由特別有用。
例如,你可以使用簽名 URL 來實現通過電子郵件發送給客戶的公開「取消訂閱」連結。要創建命名路由的簽名 URL ,請使用 URL Facade 的 signedRoute()
use Illuminate\Support\Facades\URL;
return URL::signedRoute('unsubscribe', ['user' => 1]);
如果要生成具有有效期的臨時簽名路由 URL,可以使用 temporarySignedRoute() 。當 Laravel 驗證一個臨時簽名路由 URL,它將確保被加入在簽名 URL 的過期時間戳記還沒有被改動
use Illuminate\Support\Facades\URL;
return URL::temporarySignedRoute(
'unsubscribe', now()->addMinutes(30), ['user' => 1]
);
驗證簽名路由請求
要驗證傳入請求是否具有有效簽名,你應該對傳入的 Request 呼叫 hasValidSignature()
use Illuminate\Http\Request;
Route::get('/unsubscribe/{user}', function (Request $request) {
if (! $request->hasValidSignature()) {
abort(401);
}
// ...
})->name('unsubscribe');
或者,你可以將 Illuminate\Routing\Middleware\ValidateSignature 中介層分配給路由。如果它不存在,則應該在 HTTP 內核的 routeMiddleware 陣列中為此中介層分配一個鍵
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
];
在內核中註冊中介層後,你可以將其附加到路由中。如果傳入請求沒有有效簽名,則中介層將自動返回 403 錯誤回應
Route::post('/unsubscribe/{user}', function (Request $request) {
// ...
})->name('unsubscribe')->middleware('signed');
控制器行為的 URLs
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() 定義這個參數的預設值,可以讓該參數始終存在當前請求中。然後就能從路由中介層呼叫此方法來訪問當前請求
//app\Http\Middleware\SetDefaultLocaleForUrls.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\URL;
class SetDefaultLocaleForUrls
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, Closure $next)
{
URL::defaults(['locale' => $request->user()->locale]);
return $next($request);
}
}
一旦設置了 locale 參數的預設值,你就不再需要通過幫助函式 route() 生成 URL 時傳遞它的值
URL 預設 & 中介層 優先
設定 URL 預設值會干擾 Laravel 處理隱式 Model Binding。因此你應該把你的中介層設到比 Laravel 的 SubstituteBindings 中介層優先。你能夠透過應用 HTTP 內核的 $middlewarePriority 屬性來達成,確保你的中介層擺在 SubstituteBindings 之前
再說明一次, $middlewarePriority 屬性被定義在 Illuminate\Foundation\Http\Kernerl 類別。 你能夠複製它的設定並貼入應用的 HTTP 內核檔案以修改它
/**
* The priority-sorted list of middleware.
*
* This forces non-global middleware to always be in the given order.
*
* @var array
*/
protected $middlewarePriority = [
// ...
\App\Http\Middleware\SetDefaultLocaleForUrls::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
// ...
];



