# Laravel HTTP 路由功能
- [基本路由](#basic-routing)
- [重定向路由](#redirect-routes)
- [視圖路由](#view-routes)
- [路由參數](#route-parameters)
- [必填參數](#required-parameters)
- [可選參數](#parameters-optional-parameters)
- [正則表達式約束](#parameters-regular-expression-constraints)
- [命名路由](#named-routes)
- [路由組](#route-groups)
- [中間件](#route-group-middleware)
- [命名空間](#route-group-namespaces)
- [子域名路由](#route-group-sub-domain-routing)
- [路由前綴](#route-group-prefixes)
- [路由模型綁定](#route-model-binding)
- [隱式綁定](#implicit-binding)
- [顯式綁定](#explicit-binding)
- [表單方法偽造](#form-method-spoofing)
- [訪問當前路由](#accessing-the-current-route)
<a name="basic-routing"></a>
## 基本路由
構建最基本的路由只需要一個 URI 與一個 `閉包`,這里提供了一個非常簡單優雅的定義路由的方法:
Route::get('foo', function () {
return 'Hello World';
});
#### 默認路由文件
所有的 Laravel 路由都在 `routes` 目錄中的路由文件中定義,這些文件都由框架自動加載。`routes/web.php` 文件用于定義 web 界面的路由。這里面的路由都會被分配給 `web` 中間件組,它提供了會話狀態和 CSRF 保護等功能。定義在 `routes/api.php` 中的路由都是無狀態的,并且被分配了 `api` 中間件組。
大多數的應用構建,都是以在 `routes/web.php` 文件定義路由開始的。可以通過在瀏覽器中輸入定義的路由 URL 來訪問 `routes/web.php` 中定義的路由。例如,你可以在瀏覽器中輸入 `http://your-app.dev/user` 來訪問以下路由:
Route::get('/user', 'UsersController@index');
`routes/api.php` 文件中定義的路由通過 `RouteServiceProvider` 被嵌套到一個路由組里面。在這個路由組中,會自動添加 URL 前綴 `/api` 到此文件中的每個路由,這樣你就無需再手動添加了。你可以在 `RouteServiceProvider` 類中修改此前綴以及其他路由組選項。
#### 可用的路由方法
路由器允許你注冊能響應任何 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` 方法注冊一個實現響應所有 HTTP 請求的路由:
Route::match(['get', 'post'], '/', function () {
//
});
Route::any('foo', function () {
//
});
#### CSRF 保護
指向 `web` 路由文件中定義的 `POST`、`PUT` 或 `DELETE` 路由的任何 HTML 表單都應該包含一個 CSRF 令牌字段,否則,這個請求將會被拒絕。可以在 [CSRF 文檔](/docs/{{version}}/csrf) 中閱讀有關 CSRF 保護的更多信息:
<form method="POST" action="/profile">
{{ csrf_field() }}
...
</form>
<a name="redirect-routes"></a>
### 重定向路由
如果要定義重定向到另一個 URI 的路由,可以使用 `Route::redirect` 方法。這個方法可以快速地實現重定向,而不再需要去定義完整的路由或者控制器。
Route::redirect('/here', '/there', 301);
<a name="view-routes"></a>
### 視圖路由
如果你的路由只需要返回一個視圖,可以使用 `Route::view` 方法。它和 `redirect` 一樣方便,不需要定義完整的路由或控制器。`view` 方法有三個參數,其中前兩個是必填參數,分別是 URL 和視圖名稱。第三個參數選填,可以傳入一個數組,數組中的數據會被傳遞給視圖。
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
<a name="route-parameters"></a>
## 路由參數
<a name="required-parameters"></a>
### 必填參數
當然,有時需要在路由中捕獲一些 URL 片段。例如,從 URL 中捕獲用戶的 ID,可以通過定義路由參數來執行此操作:
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
也可以根據需要在路由中定義多個參數:
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
路由的參數通常都會被放在 `{}` 內,并且參數名只能為字母,同時路由參數不能包含 `-` 符號,如果需要可以用下劃線 (`_`) 代替。路由參數會按順序依次被注入到路由回調或者控制器中,而不受回調或者控制器的參數名稱的影響。
<a name="parameters-optional-parameters"></a>
### 可選參數
有時,你可能需要指定一個路由參數,但你希望這個參數是可選的。你可以在參數后面加上 `?` 標記來實現,但前提是要確保路由的相應變量有默認值:
Route::get('user/{name?}', function ($name = null) {
return $name;
});
Route::get('user/{name?}', function ($name = 'John') {
return $name;
});
<a name="parameters-regular-expression-constraints"></a>
### 正則表達式約束
你可以使用路由實例上的 `where` 方法約束路由參數的格式。`where` 方法接受參數名稱和定義參數應如何約束的正則表達式:
Route::get('user/{name}', function ($name) {
//
})->where('name', '[A-Za-z]+');
Route::get('user/{id}', function ($id) {
//
})->where('id', '[0-9]+');
Route::get('user/{id}/{name}', function ($id, $name) {
//
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
<a name="parameters-global-constraints"></a>
#### 全局約束
如果你希望某個具體的路由參數都遵循同一個正則表達式的約束,就使用 `pattern` 方法在 `RouteServiceProvider` 的 `boot` 方法中定義這些模式:
/**
* 定義你的路由模型綁定, pattern 過濾器等。
*
* @return void
*/
public function boot()
{
Route::pattern('id', '[0-9]+');
parent::boot();
}
定義好之后,便會自動應用到所有使用該參數名稱的路由上:
Route::get('user/{id}', function ($id) {
// 僅在 {id} 為數字時執行...
});
<a name="named-routes"></a>
## 命名路由
命名路由可以方便地為指定路由生成 `URL` 或者重定向。通過在路由定義上鏈式調用 `name` 方法指定路由名稱:
Route::get('user/profile', function () {
//
})->name('profile');
你還可以指定控制器行為的路由名稱:
Route::get('user/profile', 'UserController@showProfile')->name('profile');
#### 為命名路由生成鏈接
為路由指定了名稱后,就可以使用全局輔助函數 `route` 來生成鏈接或者重定向到該路由:
// 生成 URL...
$url = route('profile');
// 生成重定向...
return redirect()->route('profile');
如果是有定義參數的命名路由,可以把參數作為 `route` 函數的第二個參數傳入,指定的參數將會自動插入到 URL 中對應的位置:
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1]);
#### 檢查當前路由
如果你想判斷當前請求是否指向了某個路由,你可以調用路由實例上的 `named` 方法。例如,你可以在路由中間件中檢查當前路由名稱:
/**
* 處理一次請求。
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->route()->named('profile')) {
//
}
return $next($request);
}
<a name="route-groups"></a>
## 路由組
路由組允許你在大量路由之間共享路由屬性,例如中間件或命名空間,而不需要為每個路由單獨定義這些屬性。共享屬性應該以數組的形式傳入 `Route::group` 方法的第一個參數中。
<a name="route-group-middleware"></a>
### 中間件
要給路由組中所有的路由分配中間件,可以在 `group` 之前調用 `middleware` 方法.中間件會依照它們在數組中列出的順序來運行:
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// 使用 first 和 second 中間件
});
Route::get('user/profile', function () {
// 使用 first 和 second 中間件
});
});
<a name="route-group-namespaces"></a>
### 命名空間
另一個常見用例是使用 `namespace` 方法將相同的 PHP 命名空間分配給路由組的中所有的控制器:
Route::namespace('Admin')->group(function () {
// 在 "App\Http\Controllers\Admin" 命名空間下的控制器
});
請記住,默認情況下,`RouteServiceProvider` 會在命名空間組中引入你的路由文件,讓你不用指定完整的 `App\Http\Controllers` 命名空間前綴就能注冊控制器路由。因此,你只需要指定命名空間 `App\Http\Controllers` 之后的部分。
<a name="route-group-sub-domain-routing"></a>
### 子域名路由
路由組也可以用來處理子域名。子域名可以像路由 URI 一樣被分配路由參數,允許你獲取一部分子域名作為參數給路由或控制器使用。可以在 `group` 之前調用 `domain` 方法來指定子域名:
Route::domain('{account}.myapp.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
<a name="route-group-prefixes"></a>
### 路由前綴
可以用 `prefix` 方法為路由組中給定的 URL 增加前綴。例如,你可以為組中所有路由的 URI 加上 `admin` 前綴:
Route::prefix('admin')->group(function () {
Route::get('users', function () {
// 匹配包含 "/admin/users" 的 URL
});
});
<a name="route-model-binding"></a>
## 路由模型綁定
當向路由或控制器行為注入模型 ID 時,就需要查詢這個 ID 對應的模型。Laravel 為路由模型綁定提供了一個直接自動將模型實例注入到路由中的方法。例如,你可以注入與給定 ID 匹配的整個 `User` 模型實例,而不是注入用戶的 ID。
<a name="implicit-binding"></a>
### 隱式綁定
Laravel 會自動解析定義在路由或控制器行為中與類型提示的變量名匹配的路由段名稱的 Eloquent 模型。例如:
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
在這個例子中,由于 `$user` 變量被類型提示為 Eloquent 模型 `App\User`,變量名稱又與 URI 中的 `{user}` 匹配,因此,Laravel 會自動注入與請求 URI 中傳入的 ID 匹配的用戶模型實例。如果在數據庫中找不到對應的模型實例,將會自動生成 404 異常。
#### 自定義鍵名
如果你想要模型綁定在檢索給定的模型類時使用除 `id` 之外的數據庫字段,你可以在 Eloquent 模型上重寫 `getRouteKeyName` 方法:
/**
* 為路由模型獲取鍵名。
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
<a name="explicit-binding"></a>
### 顯式綁定
要注冊顯式綁定,使用路由器的 `model` 方法來為給定參數指定類。在 `RouteServiceProvider` 類中的 `boot` 方法內定義這些顯式模型綁定:
public function boot()
{
parent::boot();
Route::model('user', App\User::class);
}
接著,定義一個包含 `{user}` 參數的路由:
Route::get('profile/{user}', function (App\User $user) {
//
});
因為我們已經將所有 `{user}` 參數綁定至 `App\User` 模型,所以 `User` 實例將被注入該路由。例如,`profile/1` 的請求會注入數據庫中 ID 為 1 的 `User` 實例。
如果在數據庫不存在對應 ID 的數據,就會自動拋出一個 404 異常。
#### 自定義解析邏輯
如果你想要使用自定義的解析邏輯,就使用 `Route::bind` 方法。傳遞到 `bind` 方法的閉包會接受 URI 中大括號對應的值,并且返回你想要在該路由中注入的類的實例:
public function boot()
{
parent::boot();
Route::bind('user', function ($value) {
return App\User::where('name', $value)->first();
});
}
<a name="form-method-spoofing"></a>
## 表單方法偽造
HTML 表單不支持 `PUT`、`PATCH` 或 `DELETE` 行為。所以當你要從 HTML 表單中調用定義了 `PUT`、`PATCH` 或 `DELETE` 路由時,你將需要在表單中增加隱藏的 `_method` 輸入標簽。使用 `_method` 字段的值作為 HTTP 的請求方法:
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
你也可以使用輔助函數 `method_field` 來生成隱藏的 `_method` 輸入標簽:
{{ method_field('PUT') }}
<a name="accessing-the-current-route"></a>
## 訪問當前路由
你可以使用 `Route` Facade 上的 `current`、`currentRouteName` 和 `currentRouteAction` 方法來訪問處理傳入請求的路由的信息:
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
想知道所有可訪問的方法,可以查看 API 文檔,了解 [Route facade](http://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) 和 [Route 實例](http://laravel.com/api/{{version}}/Illuminate/Routing/Route.html) 的基礎類。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@卡卡卡么](https://laravel-china.org/users/18466) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/18466_1503308973.jpeg?imageView2/1/w/100/h/100"> | 翻譯 | PHP & Python 開發工程師,[Github](https://github.com/jiannanjiang),[segmentfault](https://segmentfault.com/u/maketea) 歡迎交流 |
| [@JokerLinly](https://laravel-china.org/users/5350) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/5350_1481857380.jpg"> | Review | Stay Hungry. Stay Foolish. |
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明