---
# System prepended metadata

title: 網址生成
tags: [laravel]

---

---
tags: laravel
---
# 網址生成
![](https://i.imgur.com/xtY18rF.jpg)

## 簡介

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() 定義這個參數的預設值，可以讓該參數始終存在當前請求中。然後就能從路由中介層呼叫此方法來訪問當前請求

```
<?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,
     // ...
];
```