# HTTP 路由
- [基本路由](#basic-routing)
- [路由參數](#route-parameters)
- [必選路由參數](#required-parameters)
- [可選路由參數](#parameters-optional-parameters)
- [命名路由](#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` 中間件組,其提供了諸如 `Session` 和 `CSRF` 保護等特性。定義在 `routes/api.php` 中的路由都是無狀態的,并且會應用 `api` 中間件組。
大多數的應用,都是從 `routes/web.php` 文件開始定義路由。
#### 可用的路由方法
我們可以注冊路由來響應所有的 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 的說明在 [CSRF documentation](/docs/{{version}}/csrf):
<form method="POST" action="/profile">
{{ csrf_field() }}
...
</form>
<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="named-routes"></a>
## 命名路由
命名路由可以方便的生成 URLs 或者重定向,可以在定義路由后使用 `name` 方法實現:
Route::get('user/profile', function () {
//
})->name('profile');
還可以為控制器動作指定路由名稱:
Route::get('user/profile', 'UserController@showProfile')->name('profile');
#### 為命名路由生成 URLs
為路由指定了名稱后,我們可以使用全局輔助函數 `route` 來在生成 URLs 或者重定向到該條路由:
// Generating URLs...
$url = route('profile');
// Generating Redirects...
return redirect()->route('profile');
如果是有定義參數的命名路由,可以把參數作為 `route` 函數的第二個參數傳入,指定的參數將會自動插入到 URL 中對應的位置:
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1]);
<a name="route-groups"></a>
## 路由組
路由組允許共享路由屬性,例如中間件和命名空間等,我們沒有必要為每個路由單獨設置共有屬性,共有屬性會以數組的形式放到 `Route::group` 方法的第一個參數中。
<a name="route-group-middleware"></a>
### 中間件
要給路由組中給所有定義的路由分配中間件,可以在路由組中使用 `middleware` 鍵,中間件將會依照列表內指定的順序運行:
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Uses Auth Middleware
});
Route::get('user/profile', function () {
// Uses Auth Middleware
});
});
<a name="route-group-namespaces"></a>
### 命名空間
另一個常見的例子是,指定相同的 PHP 命名空間給控制器組。可以使用 `namespace` 參數來指定組內所有控制器的公共命名空間:
Route::group(['namespace' => 'Admin'], function() {
// Controllers Within The "App\Http\Controllers\Admin" Namespace
});
請記住,默認 `RouteServiceProvider` 會在命名空間組中引入你的路由文件,讓你不用指定完整的 `App\Http\Controllers` 命名空間前綴就能注冊控制器路由,因此,我們在定義的時候只需要指定命名空間 `App\Http\Controllers` 以后的部分。
<a name="route-group-sub-domain-routing"></a>
### 子域名路由
路由組也可以用作子域名的通配符,子域名可以像 URIs 一樣當作路由組的參數,因此允許把捕獲的子域名一部分用于我們的路由或控制器。路由組中子域名的屬性可以使用路由組屬性的 `domain` 鍵。
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
<a name="route-group-prefixes"></a>
### 路由前綴
通過路由組數組屬性中的 `prefix` 鍵可以給每個路由組中的路由加上指定的 URI 前綴,例如,我們可以給路由組中所有的 URIs 加上路由前綴 `admin` :
Route::group(['prefix' => 'admin'], function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
<a name="route-model-binding"></a>
## 路由模型綁定
當注入模型 ID 到路由控制器時,我們通常需要查詢這個 ID 對應的模型,Laravel 路由模型綁定提供了一個方便的方法自動將模型注入到我們的路由中,例如,除了注入一個用戶的 ID,你也可以注入與指定 ID 相符的完整 `User` 類實例。
<a name="implicit-binding"></a>
### 隱式綁定
Laravel 會自動解析定義在路由或控制器動作(變量名匹配路由片段)中的 Eloquent 模型類型聲明,例如:
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
在這個例子中,由于類型聲明了 Eloquent 模型 `App\User`,對應的變量名 `$user` 會匹配路由片段中的 `{user}`,這樣,Laravel 會自動注入與請求 URI 中傳入的 ID 對應的用戶模型實例。
如果數據庫中找不到對應的模型實例,將會自動生成產生一個 404 HTTP 響應。
#### 自定義鍵名
如果你想要隱式模型綁定除 `id` 以外的數據庫字段,你可以重寫 Eloquent 模型類的 `getRouteKeyName` 方法:
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
<a name="explicit-binding"></a>
### 顯式綁定
可以使用 `router` 的 `model` 方法來注冊顯式綁定。你應該在 `RouteServiceProvider` 類中的 `boot` 方法內定義這些顯式綁定:
#### 綁定參數至模型
public function boot()
{
parent::boot();
Route::model('user', 'App\User');
}
接著,定義包含 `{user}` 參數的路由
$router->get('profile/{user}', function(App\User $user) {
//
});
因為我們已經綁定 `{user}` 參數至 `App\User` 模型,所以 `User` 實例會被注入至該路由。所以,舉個例子,一個至 `profile/1` 的請求會注入 ID 為 1 的 `User` 實例。
> **注意:**如果在數據庫不存在對應 ID 的數據,就會自動拋出一個 404 異常。
#### 自定義解析邏輯
如果你想要使用自定義的解析邏輯,需要使用 `Route::bind` 方法,傳遞到 `bind` 方法的閉包會獲取到 URI 請求參數中的值,并且返回你想要在該路由中注入的類實例:
$router->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>
你也可以使用輔助函數 `methid_field` 來生成隱藏的輸入字段 `_method`:
{{ method_field('PUT') }}
<a name="accessing-the-current-route"></a>
## 獲取當前路由信息
你可以使用 `Route` 上的 `current`, `currentRouteName`, and `currentRouteAction` 方法來訪問處理當前輸入請求的路由信息:
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
完整的方法列表請參考 [Route facade](http://laravel.com/api/{{version}}/Illuminate/Routing/Router.html) 和 [Route 實例](http://laravel.com/api/{{version}}/Illuminate/Routing/Route.html)
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@kzh4435](https://phphub.org/users/5698) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/5698_1473126483.jpeg?imageView2/1/w/100/h/100"> | 翻譯 | 努力學習PHP |
| [@overtrue](https://github.com/overtrue) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/76_1451276555.png?imageView2/1/w/100/h/100"> | Review | 大家可以 [加我微博](http://weibo.com/joychaocc) 保持聯系 |
| [@JobsLong](https://github.com/JobsLong) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/56_1427370654.jpeg?imageView2/1/w/100/h/100"> | Review | |
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- 錯誤與日志
- 開發環境
- HomeStead
- Valet
- 核心概念
- 服務容器
- 服務提供者
- 門面(facades)
- contracts
- HTTP層
- 路由
- 中間件
- CSRF保護
- 控制器
- 請求
- 響應
- Session
- 表單驗證
- 視圖與模板
- 視圖
- Blade模板
- 本地化
- Javascript與CSS
- 入門指南
- laravel-elixir
- 安全
- 用戶認證
- 用戶授權
- 重置密碼
- API授權
- 加密解密
- 哈希
- 綜合話題
- 廣播系統
- 緩存系統
- 事件系統
- 文件存儲
- 郵件發送
- 消息通知
- 隊列
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent集合
- 修改器
- 序列化
- Artisan控制臺
- Artisan 命令行
- 任務調度
- 測試
- 快速入門
- 應用程序測試
- 數據庫測試
- 模擬器
- 官方擴展包
- Cashier交易包
- Envoy 部署工具
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 附錄
- 集合
- 輔助函數
- 擴展包開發
- 交流說明